home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 April / enter-2004-04.iso / files / httrack-3.30.exe / {app} / src / htsparse.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-10-11  |  172.3 KB  |  3,964 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: htsparse.c parser                                      */
  34. /*       html/javascript/css parser                             */
  35. /*       and other parser routines                              */
  36. /* Author: Xavier Roche                                         */
  37. /* ------------------------------------------------------------ */
  38.  
  39.  
  40.  
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <time.h>
  45. #include <fcntl.h>
  46. #include <ctype.h>
  47.  
  48. /* File defs */
  49. #include "htscore.h"
  50.  
  51. /* specific definitions */
  52. #include "htsbase.h"
  53. #include "htsnet.h"
  54. #include "htsbauth.h"
  55. #include "htsmd5.h"
  56. #include "htsindex.h"
  57.  
  58. /* external modules */
  59. #include "htsmodules.h"
  60.  
  61. // htswrap_add
  62. #include "htswrap.h"
  63.  
  64. // parser
  65. #include "htsparse.h"
  66.  
  67.  
  68. // specific defines
  69. #define urladr   (liens[ptr]->adr)
  70. #define urlfil   (liens[ptr]->fil)
  71. #define savename (liens[ptr]->sav)
  72. #define parenturladr   (liens[liens[ptr]->precedent]->adr)
  73. #define parenturlfil   (liens[liens[ptr]->precedent]->fil)
  74. #define parentsavename (liens[liens[ptr]->precedent]->sav)
  75. #define relativeurladr   ((!parent_relative)?urladr:parenturladr)
  76. #define relativeurlfil   ((!parent_relative)?urlfil:parenturlfil)
  77. #define relativesavename ((!parent_relative)?savename:parentsavename)
  78.  
  79. #define test_flush if (opt->flush) { if (opt->log) { fflush(opt->log); } if (opt->errlog) { fflush(opt->errlog);  } }
  80.  
  81. // does nothing
  82. #define XH_uninit do {} while(0)
  83.  
  84. // version optimisΘe, qui permet de ne pas toucher aux html non modifiΘs (update)
  85. #define REALLOC_SIZE 8192
  86. #define HT_ADD_CHK(A) if (((int) (A)+ht_len+1) >= ht_size) { \
  87.   ht_size=(A)+ht_len+REALLOC_SIZE; \
  88.   ht_buff=(char*) realloct(ht_buff,ht_size); \
  89.   if (ht_buff==NULL) { \
  90.   printf("PANIC! : Not enough memory [%d]\n",__LINE__); \
  91.   XH_uninit; \
  92.   abortLogFmt("not enough memory for current html document in HT_ADD_CHK : realloct(%d) failed" _ ht_size); \
  93.   exit(1); \
  94.   } \
  95.   } \
  96.   ht_len+=A;
  97. #define HT_ADD_ADR \
  98.   if ((opt->getmode & 1) && (ptr>0)) { \
  99.   int i=((int) (adr - lastsaved)),j=ht_len; HT_ADD_CHK(i) \
  100.   memcpy(ht_buff+j, lastsaved, i); \
  101.   ht_buff[j+i]='\0'; \
  102.   lastsaved=adr; \
  103.   }
  104. #define HT_ADD(A) \
  105.   if ((opt->getmode & 1) && (ptr>0)) { \
  106.   int i=strlen(A),j=ht_len; \
  107.   if (i) { \
  108.   HT_ADD_CHK(i) \
  109.   memcpy(ht_buff+j, A, i); \
  110.   ht_buff[j+i]='\0'; \
  111.   } }
  112. #define HT_ADD_START \
  113.   int ht_size=(int)(r->size*5)/4+REALLOC_SIZE; \
  114.   int ht_len=0; \
  115.   char* ht_buff=NULL; \
  116.   if ((opt->getmode & 1) && (ptr>0)) { \
  117.   ht_buff=(char*) malloct(ht_size); \
  118.   if (ht_buff==NULL) { \
  119.   printf("PANIC! : Not enough memory [%d]\n",__LINE__); \
  120.   XH_uninit; \
  121.   abortLogFmt("not enough memory for current html document in HT_ADD_START : malloct(%d) failed" _ ht_size); \
  122.   exit(1); \
  123.   } \
  124.   ht_buff[0]='\0'; \
  125.   }
  126. #define HT_ADD_END { \
  127.   int ok=0;\
  128.   if (ht_buff) { \
  129.   INTsys file_len=(INTsys) strlen(ht_buff);\
  130.   char digest[32+2];\
  131.   digest[0]='\0';\
  132.   domd5mem(ht_buff,file_len,digest,1);\
  133.   if (fsize(fconv(savename))==file_len) { \
  134.   int mlen;\
  135.   char* mbuff;\
  136.   cache_readdata(cache,"//[HTML-MD5]//",savename,&mbuff,&mlen);\
  137.   if (mlen) mbuff[mlen]='\0';\
  138.   if ((mlen == 32) && (strcmp(((mbuff!=NULL)?mbuff:""),digest)==0)) {\
  139.   ok=1;\
  140.   if ( (opt->debug>1) && (opt->log!=NULL) ) {\
  141.   fspc(opt->log,"debug"); fprintf(opt->log,"File not re-written (md5): %s"LF,savename);\
  142.   test_flush;\
  143.   }\
  144.   } else {\
  145.   ok=0;\
  146.   } \
  147.   }\
  148.   if (!ok) { \
  149.   fp=filecreate(savename); \
  150.   if (fp) { \
  151.   if (file_len>0) {\
  152.   if ((INTsys)fwrite(ht_buff,1,file_len,fp) != file_len) { \
  153.   int fcheck;\
  154.   if ((fcheck=check_fatal_io_errno())) {\
  155.   opt->state.exit_xh=-1;\
  156.   }\
  157.   if (opt->errlog) {   \
  158.   fspc(opt->errlog,"error"); fprintf(opt->errlog,"Unable to write HTML file %s: %s"LF, savename, strerror(errno));\
  159.   if (fcheck) {\
  160.   fspc(opt->errlog,"error");\
  161.   fprintf(opt->errlog,"* * Fatal write error, giving up"LF);\
  162.   }\
  163.   test_flush;\
  164.   }\
  165.   }\
  166.   }\
  167.   fclose(fp); fp=NULL; \
  168.   if (strnotempty(r->lastmodified)) \
  169.   set_filetime_rfc822(savename,r->lastmodified); \
  170.   } else {\
  171.   int fcheck;\
  172.   if ((fcheck=check_fatal_io_errno())) {\
  173.   opt->state.exit_xh=-1;\
  174.   }\
  175.   if (opt->errlog) { \
  176.   fspc(opt->errlog,"error");\
  177.   fprintf(opt->errlog,"Unable to save file %s : %s"LF, savename, strerror(errno));\
  178.   if (fcheck) {\
  179.   fspc(opt->errlog,"error");\
  180.   fprintf(opt->errlog,"* * Fatal write error, giving up"LF);\
  181.   }\
  182.   test_flush;\
  183.   }\
  184.   }\
  185.   } else {\
  186.   filenote(savename,NULL); \
  187.   }\
  188.   if (cache->ndx)\
  189.     cache_writedata(cache->ndx,cache->dat,"//[HTML-MD5]//",savename,digest,(int)strlen(digest));\
  190.   } \
  191.   freet(ht_buff); ht_buff=NULL; \
  192.   }
  193. #define HT_ADD_FOP 
  194.  
  195. // COPY IN HTSCORE.C
  196. #define HT_INDEX_END do { \
  197. if (!makeindex_done) { \
  198. if (makeindex_fp) { \
  199.   char tempo[1024]; \
  200.   if (makeindex_links == 1) { \
  201.     sprintf(tempo,"<meta HTTP-EQUIV=\"Refresh\" CONTENT=\"0; URL=%s\">"CRLF,makeindex_firstlink); \
  202.   } else \
  203.     tempo[0]='\0'; \
  204.   fprintf(makeindex_fp,template_footer, \
  205.     "<!-- Mirror and index made by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->", \
  206.     tempo \
  207.     ); \
  208.   fflush(makeindex_fp); \
  209.   fclose(makeindex_fp);  /* α ne pas oublier sinon on passe une nuit blanche */  \
  210.   makeindex_fp=NULL; \
  211.   usercommand(opt,0,NULL,fconcat(opt->path_html,"index.html"),"primary","primary");  \
  212. } \
  213. } \
  214. makeindex_done=1;    /* ok c'est fait */  \
  215. } while(0)
  216.  
  217. // Enregistrement d'un lien:
  218. // on calcule la taille nΘcessaire: taille des 3 chaεnes α stocker (taille forcΘe paire, plus 2 octets de sΘcuritΘ)
  219. // puis on vΘrifie qu'on a assez de marge dans le buffer - sinon on en rΘalloue un autre
  220. // enfin on Θcrit α l'adresse courante du buffer, qu'on incrΘmente. on dΘcrΘmente la taille dispo d'autant ensuite
  221. // codebase: si non nul et si .class stockee on le note pour chemin primaire pour classes
  222. // FA,FS: former_adr et former_fil, lien original
  223. #if HTS_HASH
  224. #define liens_record_sav_len(A) 
  225. #else
  226. #define liens_record_sav_len(A) (A)->sav_len=strlen((A)->sav)
  227. #endif
  228.  
  229. // COPIE DE HTSCORE.C
  230. #define liens_record(A,F,S,FA,FF) { \
  231. int notecode=0; \
  232. int lienurl_len=((sizeof(lien_url)+HTS_ALIGN-1)/HTS_ALIGN)*HTS_ALIGN,\
  233.   adr_len=strlen(A),\
  234.   fil_len=strlen(F),\
  235.   sav_len=strlen(S),\
  236.   cod_len=0,\
  237.   former_adr_len=strlen(FA),\
  238.   former_fil_len=strlen(FF); \
  239. if (former_adr_len>0) {\
  240.   former_adr_len=(former_adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  241.   former_fil_len=(former_fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  242. } else former_adr_len=former_fil_len=0;\
  243. if (strlen(F)>6) if (strnotempty(codebase)) if (strfield(F+strlen(F)-6,".class")) { notecode=1; \
  244. cod_len=strlen(codebase); cod_len=(cod_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; } \
  245. adr_len=(adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; fil_len=(fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; sav_len=(sav_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  246. if ((int) lien_size < (int) (adr_len+fil_len+sav_len+cod_len+former_adr_len+former_fil_len+lienurl_len)) { \
  247. lien_buffer=(char*) ((void*) calloct(add_tab_alloc,1)); \
  248. lien_size=add_tab_alloc; \
  249. if (lien_buffer!=NULL) { \
  250. liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=lienurl_len; lien_size-=lienurl_len; \
  251. liens[lien_tot]->firstblock=1; \
  252. } \
  253. } else { \
  254. liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=lienurl_len; lien_size-=lienurl_len; \
  255. liens[lien_tot]->firstblock=0; \
  256. } \
  257. if (liens[lien_tot]!=NULL) { \
  258. liens[lien_tot]->adr=lien_buffer; lien_buffer+=adr_len; lien_size-=adr_len; \
  259. liens[lien_tot]->fil=lien_buffer; lien_buffer+=fil_len; lien_size-=fil_len; \
  260. liens[lien_tot]->sav=lien_buffer; lien_buffer+=sav_len; lien_size-=sav_len; \
  261. liens[lien_tot]->cod=NULL; \
  262. if (notecode) { liens[lien_tot]->cod=lien_buffer; lien_buffer+=cod_len; lien_size-=cod_len; strcpybuff(liens[lien_tot]->cod,codebase); } \
  263. if (former_adr_len>0) {\
  264. liens[lien_tot]->former_adr=lien_buffer; lien_buffer+=former_adr_len; lien_size-=former_adr_len; \
  265. liens[lien_tot]->former_fil=lien_buffer; lien_buffer+=former_fil_len; lien_size-=former_fil_len; \
  266. strcpybuff(liens[lien_tot]->former_adr,FA); \
  267. strcpybuff(liens[lien_tot]->former_fil,FF); \
  268. }\
  269. strcpybuff(liens[lien_tot]->adr,A); \
  270. strcpybuff(liens[lien_tot]->fil,F); \
  271. strcpybuff(liens[lien_tot]->sav,S); \
  272. liens_record_sav_len(liens[lien_tot]); \
  273. hash_write(hashptr,lien_tot,opt->urlhack);  \
  274. } \
  275. }
  276.  
  277. #define ENGINE_LOAD_CONTEXT() \
  278.   lien_url** liens = (lien_url**) str->liens; \
  279.   httrackp* opt = (httrackp*) str->opt; \
  280.   lien_back* back = (lien_back*) str->back; \
  281.   cache_back* cache = (cache_back*) str->cache; \
  282.   hash_struct* hashptr = (hash_struct*) str->hashptr; \
  283.   int back_max = str->back_max; \
  284.   int numero_passe = str->numero_passe; \
  285.   int add_tab_alloc = str->add_tab_alloc; \
  286.   /* */ \
  287.   int lien_tot = * ( (int*) (str->lien_tot_) ); \
  288.   int ptr = * ( (int*) (str->ptr_) ); \
  289.   int lien_size = * ( (int*) (str->lien_size_) ); \
  290.   char* lien_buffer = * ( (char**) (str->lien_buffer_) ); \
  291.   /* */ \
  292.   /* */ \
  293.   htsblk* r = stre->r_; \
  294.   hash_struct* hash = stre->hash_; \
  295.   int lien_max = *stre->lien_max_; \
  296.   /* */ \
  297.   int error = * stre->error_; \
  298.   int store_errpage = * stre->store_errpage_; \
  299.   char* codebase = stre->codebase; \
  300.   char* base = stre->base; \
  301.   /* */ \
  302.   int makeindex_done = *stre->makeindex_done_; \
  303.   FILE* makeindex_fp = *stre->makeindex_fp_; \
  304.   int makeindex_links = *stre->makeindex_links_; \
  305.   char* makeindex_firstlink = stre->makeindex_firstlink_; \
  306.   /* */ \
  307.   char *template_header = stre->template_header_; \
  308.   char *template_body = stre->template_body_; \
  309.   char *template_footer = stre->template_footer_; \
  310.   /* */ \
  311.   LLint stat_fragment = *stre->stat_fragment_; \
  312.   TStamp makestat_time = stre->makestat_time; \
  313.   FILE* makestat_fp = stre->makestat_fp
  314.  
  315. #define ENGINE_SAVE_CONTEXT() \
  316.   /* Apply changes */ \
  317.    * ( (int*) (str->lien_tot_) ) = lien_tot; \
  318.    * ( (int*) (str->ptr_) ) = ptr; \
  319.    * ( (int*) (str->lien_size_) ) = lien_size; \
  320.    * ( (char**) (str->lien_buffer_) ) = lien_buffer; \
  321.    /* */ \
  322.    * stre->error_ = error; \
  323.    * stre->store_errpage_ = store_errpage; \
  324.    * stre->lien_max_ = lien_max; \
  325.    /* */ \
  326.    *stre->makeindex_done_ = makeindex_done; \
  327.    *stre->makeindex_fp_ = makeindex_fp; \
  328.    *stre->makeindex_links_ = makeindex_links; \
  329.    /* */ \
  330.    *stre->stat_fragment_ = stat_fragment
  331.  
  332. #define _FILTERS     (*opt->filters.filters)
  333. #define _FILTERS_PTR (opt->filters.filptr)
  334. #define _ROBOTS      ((robots_wizard*)opt->robotsptr)
  335.  
  336.  
  337. /* Main parser */
  338. int htsparse(htsmoduleStruct* str, htsmoduleStructExtended* stre) {
  339.   /* Load engine variables */
  340.   ENGINE_LOAD_CONTEXT();
  341.   
  342. #if HTS_ANALYSTE
  343.   if (hts_htmlcheck(r->adr,(int)r->size,urladr,urlfil)) {
  344. #endif          
  345.     FILE* fp=NULL;      // fichier Θcrit localement 
  346.     char* adr=r->adr;    // pointeur (on parcourt)
  347.     char* lastsaved;    // adresse du dernier octet sauvΘ + 1
  348.     if ( (opt->debug>1) && (opt->log!=NULL) ) {
  349.       fspc(opt->log,"debug"); fprintf(opt->log,"scan file.."LF); test_flush;
  350.     }
  351.     
  352.     
  353.     // Indexing!
  354. #if HTS_MAKE_KEYWORD_INDEX
  355.     if (opt->kindex) {
  356.       if (index_keyword(r->adr,r->size,r->contenttype,savename,opt->path_html)) {
  357.         if ( (opt->debug>1) && (opt->log!=NULL) ) {
  358.           fspc(opt->log,"debug"); fprintf(opt->log,"indexing file..done"LF); test_flush;
  359.         }
  360.       } else {
  361.         if ( (opt->debug>1) && (opt->log!=NULL) ) {
  362.           fspc(opt->log,"debug"); fprintf(opt->log,"indexing file..error!"LF); test_flush;
  363.         }
  364.       }
  365.     }
  366. #endif
  367.     
  368.     // Now, parsing
  369.     if ((opt->getmode & 1) && (ptr>0)) {  // rΘcupΘrer les html sur disque       
  370.       // crΘer le fichier html local
  371.       HT_ADD_FOP;   // Θcrire peu α peu le fichier
  372.     }
  373.     
  374.     if (!error) {
  375.       int detect_title=0;  // dΘtection  du title
  376.       int back_add_stats = opt->state.back_add_stats;
  377.       //
  378.       char* in_media=NULL; // in other media type (real media and so..)
  379.       int intag=0;         // on est dans un tag
  380.       int incomment=0;     // dans un <!--
  381.       int inscript=0;      // dans un scipt pour applets javascript)
  382.       signed char inscript_state[10][257];
  383.       typedef enum { 
  384.         INSCRIPT_START=0,
  385.         INSCRIPT_ANTISLASH,
  386.         INSCRIPT_INQUOTE,
  387.         INSCRIPT_INQUOTE2,
  388.         INSCRIPT_SLASH,
  389.         INSCRIPT_SLASHSLASH,
  390.         INSCRIPT_COMMENT,
  391.         INSCRIPT_COMMENT2,
  392.         INSCRIPT_ANTISLASH_IN_QUOTE,
  393.         INSCRIPT_ANTISLASH_IN_QUOTE2,
  394.         INSCRIPT_DEFAULT=256
  395.       } INSCRIPT;
  396.       INSCRIPT inscript_state_pos=INSCRIPT_START;
  397.       char* inscript_name=NULL; // script tag name
  398.       int inscript_tag=0;  // on est dans un <body onLoad="... terminΘ par >
  399.       char inscript_tag_lastc='\0';
  400.       // terminaison (" ou ') du "<body onLoad=.."
  401.       int inscriptgen=0;     // on est dans un code gΘnΘrant, ex aprΦs obj.write("..
  402.       //int inscript_check_comments=0, inscript_in_comments=0;    // javascript comments
  403.       char scriptgen_q='\0'; // caractΦre faisant office de guillemet (' ou ")
  404.       int no_esc_utf=0;      // ne pas echapper chars > 127
  405.       int nofollow=0;        // ne pas scanner
  406.       //
  407.       int parseall_lastc='\0';     // dernier caractΦre parsΘ pour parseall
  408.       //int parseall_incomment=0;   // dans un /* */ (exemple: a = /* URL */ "img.gif";)
  409.       //
  410.       char* intag_start=adr;
  411.       char* intag_startattr=NULL;
  412.       int intag_start_valid=0;
  413.       //
  414.       int   parent_relative=0;    // the parent is the base path (.js, .css..)
  415.       HT_ADD_START;    // dΘbuter
  416.   
  417.       /* Initialize script automate for comments, quotes.. */
  418.       memset(inscript_state, 0xff, sizeof(inscript_state));
  419.       inscript_state[INSCRIPT_START][INSCRIPT_DEFAULT]=INSCRIPT_START;     /* by default, stay in START */
  420.       inscript_state[INSCRIPT_START]['\\']=INSCRIPT_ANTISLASH;             /* #1: \ escapes the next character whatever it is */
  421.       inscript_state[INSCRIPT_ANTISLASH][INSCRIPT_DEFAULT]=INSCRIPT_START;
  422.       inscript_state[INSCRIPT_START]['\'']=INSCRIPT_INQUOTE;               /* #2: ' opens quote and only ' returns to 0 */
  423.       inscript_state[INSCRIPT_INQUOTE][INSCRIPT_DEFAULT]=INSCRIPT_INQUOTE;
  424.       inscript_state[INSCRIPT_INQUOTE]['\'']=INSCRIPT_START;
  425.       inscript_state[INSCRIPT_INQUOTE]['\\']=INSCRIPT_ANTISLASH_IN_QUOTE;
  426.       inscript_state[INSCRIPT_START]['\"']=INSCRIPT_INQUOTE2;              /* #3: " opens double-quote and only " returns to 0 */
  427.       inscript_state[INSCRIPT_INQUOTE2][INSCRIPT_DEFAULT]=INSCRIPT_INQUOTE2;
  428.       inscript_state[INSCRIPT_INQUOTE2]['\"']=INSCRIPT_START;
  429.       inscript_state[INSCRIPT_INQUOTE2]['\\']=INSCRIPT_ANTISLASH_IN_QUOTE2;
  430.       inscript_state[INSCRIPT_START]['/']=INSCRIPT_SLASH;                  /* #4: / state, default to #0 */
  431.       inscript_state[INSCRIPT_SLASH][INSCRIPT_DEFAULT]=INSCRIPT_START;
  432.       inscript_state[INSCRIPT_SLASH]['/']=INSCRIPT_SLASHSLASH;             /* #5: // with only LF to escape */
  433.       inscript_state[INSCRIPT_SLASHSLASH][INSCRIPT_DEFAULT]=INSCRIPT_SLASHSLASH;
  434.       inscript_state[INSCRIPT_SLASHSLASH]['\n']=INSCRIPT_START;
  435.       inscript_state[INSCRIPT_SLASH]['*']=INSCRIPT_COMMENT;                /* #6: / * with only * / to escape */
  436.       inscript_state[INSCRIPT_COMMENT][INSCRIPT_DEFAULT]=INSCRIPT_COMMENT;
  437.       inscript_state[INSCRIPT_COMMENT]['*']=INSCRIPT_COMMENT2;             /* #7: closing comments */
  438.       inscript_state[INSCRIPT_COMMENT2][INSCRIPT_DEFAULT]=INSCRIPT_COMMENT;
  439.       inscript_state[INSCRIPT_COMMENT2]['/']=INSCRIPT_START;
  440.       inscript_state[INSCRIPT_COMMENT2]['*']=INSCRIPT_COMMENT2;
  441.       inscript_state[INSCRIPT_ANTISLASH_IN_QUOTE][INSCRIPT_DEFAULT]=INSCRIPT_INQUOTE;    /* #8: escape in "" */
  442.       inscript_state[INSCRIPT_ANTISLASH_IN_QUOTE2][INSCRIPT_DEFAULT]=INSCRIPT_INQUOTE2;  /* #9: escape in '' */
  443.  
  444.  
  445.       /* statistics */
  446.       if ((opt->getmode & 1) && (ptr>0)) { 
  447.       /*
  448.       HTS_STAT.stat_files++;
  449.       HTS_STAT.stat_bytes+=r->size;
  450.         */
  451.       }
  452.       
  453.       /* Primary list or URLs */
  454.       if (ptr == 0) {
  455.         intag=1;
  456.         intag_start_valid=0;
  457.       }
  458.       /* Check is the file is a .js file */
  459.       else if (
  460.         (strfield2(r->contenttype,"application/x-javascript")!=0)
  461.         || (strfield2(r->contenttype,"text/css")!=0)
  462.         ) {      /* JavaScript js file */
  463.         inscript=1; 
  464.         inscript_name="script";
  465.         intag=1;     // because aprΦs <script> on y est .. - pas utile
  466.         intag_start_valid=0;    // OUI car nous sommes dans du code, plus dans du "vrai" tag
  467.         if ((opt->debug>1) && (opt->log!=NULL)) {
  468.           fspc(opt->log,"debug"); fprintf(opt->log,"note: this file is a javascript file"LF); test_flush;
  469.         }
  470.         // all links must be checked against parent, not this link
  471.         if (liens[ptr]->precedent != 0) {
  472.           parent_relative=1;
  473.         }
  474.       }
  475.       /* Or a real audio */
  476.       else if (strfield2(r->contenttype,"audio/x-pn-realaudio")!=0) {      /* realaudio link file */
  477.         inscript=intag=1;
  478.         inscript_name="media";
  479.         intag_start_valid=0;
  480.         in_media="RAM";       // real media!
  481.       }
  482.       // Detect UTF8 format
  483.       if (is_unicode_utf8((unsigned char*) r->adr, (unsigned int) r->size) == 1) {
  484.         no_esc_utf=1;
  485.       } else {
  486.         no_esc_utf=0;
  487.       }
  488.       // Hack to prevent any problems with ram files of other files
  489.       * ( r->adr + r->size ) = '\0';
  490.       
  491.       
  492.       // ------------------------------------------------------------
  493.       // analyser ce qu'il y a en mΘmoire (fichier html)
  494.       // on scanne les balises
  495.       // ------------------------------------------------------------
  496. #if HTS_ANALYSTE
  497.       _hts_in_html_done=0;     // 0% scannΘs
  498.       _hts_cancel=0;           // pas de cancel
  499.       _hts_in_html_parsing=1;  // flag pour indiquer un parsing
  500. #endif
  501.       base[0]='\0';    // effacer base-href
  502.       lastsaved=adr;
  503.       do {
  504.         int p=0;
  505.         int valid_p=0;      // force to take p even if == 0
  506.         int ending_p='\0';  // ending quote?
  507.         int archivetag_p=0;  // avoid multiple-archives with commas
  508.         INSCRIPT inscript_state_pos_prev=inscript_state_pos;
  509.         error=0;
  510.         
  511.         /* Hack to avoid NULL char problems with C syntax */
  512.         /* Yes, some bogus HTML pages can embed null chars
  513.         and therefore can not be properly handled if this hack is not done
  514.         */
  515.         if ( ! (*adr) ) {
  516.           if ( ((int) (adr - r->adr)) < r->size)
  517.             *adr=' ';
  518.         }
  519.         
  520.         
  521.         
  522.         /*
  523.         index.html built here
  524.         */
  525.         // Construction index.html (sommaire)
  526.         // Avant de tester les a href,
  527.         // Ici on teste si l'on doit construire l'index vers le(s) site(s) miroir(s)
  528.         if (!makeindex_done) {  // autoriation d'Θcrire un index
  529.           if (!detect_title) {
  530.             if (opt->depth == liens[ptr]->depth) {    // on note toujours les premiers liens
  531.               if (!in_media) {
  532.                 if (opt->makeindex && (ptr>0)) {
  533.                   if (opt->getmode & 1) {  // autorisation d'Θcrire
  534.                     p=strfield(adr,"title");  
  535.                     if (p) {
  536.                       if (*(adr-1)=='/') p=0;    // /title
  537.                     } else {
  538.                       if (strfield(adr,"/html"))
  539.                         p=-1;                    // noter, mais sans titre
  540.                       else if (strfield(adr,"body"))
  541.                         p=-1;                    // noter, mais sans titre
  542.                       else if ( ((int) (adr - r->adr) ) >= (r->size-1) )
  543.                         p=-1;                    // noter, mais sans titre
  544.                       else if ( (int) (adr - r->adr) >= r->size - 2)   // we got to hurry
  545.                         p=-1; // xxc xxc xxc
  546.                     }
  547.                   } else
  548.                     p=0;
  549.                   
  550.                   if (p) {    // ok center                            
  551.                     if (makeindex_fp==NULL) {
  552.                       verif_backblue(opt,opt->path_html);    // gΘnΘrer gif
  553.                       makeindex_fp=filecreate(fconcat(opt->path_html,"index.html"));
  554.                       if (makeindex_fp!=NULL) {
  555.                         
  556.                         // Header
  557.                         fprintf(makeindex_fp,template_header,
  558.                           "<!-- Mirror and index made by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->"
  559.                           );
  560.                         
  561.                       } else makeindex_done=-1;    // fait, erreur
  562.                     }
  563.                     
  564.                     if (makeindex_fp!=NULL) {
  565.                       char tempo[HTS_URLMAXSIZE*2];
  566.                       char s[HTS_URLMAXSIZE*2];
  567.                       char* a=NULL;
  568.                       char* b=NULL;
  569.                       s[0]='\0';
  570.                       if (p>0) {
  571.                         a=strchr(adr,'>');
  572.                         if (a!=NULL) {
  573.                           a++;
  574.                           while(is_space(*a)) a++;    // sauter espaces & co
  575.                           b=strchr(a,'<');   // prochain tag
  576.                         }
  577.                       }
  578.                       if (lienrelatif(tempo,liens[ptr]->sav,concat(opt->path_html,"index.html"))==0) {
  579.                         detect_title=1;      // ok dΘtectΘ pour cette page!
  580.                         makeindex_links++;   // un de plus
  581.                         strcpybuff(makeindex_firstlink,tempo);
  582.                         //
  583.  
  584.                         /* Hack */
  585.                         if (opt->mimehtml) {
  586.                           strcpybuff(makeindex_firstlink, "cid:primary/primary");
  587.                         }
  588.  
  589.                         if ((b==a) || (a==NULL) || (b==NULL)) {    // pas de titre
  590.                           strcpybuff(s,tempo);
  591.                         } else if ((b-a)<256) {
  592.                           b--;
  593.                           while(is_space(*b)) b--;
  594.                           strncpy(s,a,b-a+1);
  595.                           *(s+(b-a)+1)='\0';
  596.                         }
  597.                         
  598.                         // Body
  599.                         fprintf(makeindex_fp,template_body,
  600.                           tempo,
  601.                           s
  602.                           );
  603.                         
  604.                       }
  605.                     }
  606.                   }
  607.                 }
  608.               }
  609.               
  610.             } else if (liens[ptr]->depth<opt->depth) {   // on a sautΘ level1+1 et level1
  611.               HT_INDEX_END;
  612.             }
  613.           } // if (opt->makeindex)
  614.         }
  615.         // FIN Construction index.html (sommaire)
  616.         /*
  617.         end -- index.html built here
  618.         */
  619.         
  620.         
  621.         
  622.         /* Parse */
  623.         if (
  624.           (*adr=='<')    /* No starting tag */
  625.           && (!inscript)    /* Not in (java)script */
  626.           && (!incomment)   /* Not in comment (<!--) */
  627.           ) { 
  628.           intag=1;
  629.           //parseall_incomment=0;
  630.           //inquote=0;  // effacer quote
  631.           intag_start=adr; intag_start_valid=1;
  632.           codebase[0]='\0';    // effacer Θventuel codebase
  633.           
  634.           if (opt->getmode & 1) {  // sauver html
  635.             p=strfield(adr,"</html");
  636.             if (p==0) p=strfield(adr,"<head>");
  637.             // if (p==0) p=strfield(adr,"<doctype");
  638.             if (p) {
  639.               char* eol="\n";
  640.               if (strchr(r->adr,'\r'))
  641.                 eol="\r\n";
  642.               if (strnotempty(opt->footer)) {
  643.                 char tempo[1024+HTS_URLMAXSIZE*2];
  644.                 char gmttime[256];
  645.                 tempo[0]='\0';
  646.                 time_gmt_rfc822(gmttime);
  647.                 strcatbuff(tempo,eol);
  648.                 sprintf(tempo+strlen(tempo),opt->footer,jump_identification(urladr),urlfil,gmttime,HTTRACK_VERSIONID,"","","","","","","");
  649.                 strcatbuff(tempo,eol);
  650.                 //fwrite(tempo,1,strlen(tempo),fp);
  651.                 HT_ADD(tempo);
  652.               }
  653.               if (r->charset[0]) {
  654.                 HT_ADD("<meta http-equiv=\"content-type\" content=\"text/html;charset=");
  655.                 HT_ADD(r->charset);
  656.                 HT_ADD("\">");
  657.                 HT_ADD(eol);
  658.               }
  659.             }
  660.           }        
  661.           
  662.           // Θliminer les <!-- (commentaires) : intag dΘvalidΘ
  663.           if (*(adr+1)=='!')
  664.             if (*(adr+2)=='-')
  665.               if (*(adr+3)=='-') {
  666.                 intag=0;
  667.                 incomment=1;
  668.                 intag_start_valid=0;
  669.               }
  670.               
  671.         }
  672.         else if (
  673.           (*adr=='>')                        /* ending tag */
  674.           && ( (!inscript) || (inscript_tag) )  /* and in tag (or in script) */
  675.           ) {
  676.           if (inscript_tag) {
  677.             inscript_tag=inscript=0;
  678.             intag=0;
  679.             incomment=0;
  680.             intag_start_valid=0;
  681.           } else if (!incomment) {
  682.             intag=0; //inquote=0;
  683.             
  684.             // entrΘe dans du javascript?
  685.             // on parse ICI car il se peut qu'on ait eu a parser les src=.. dedans
  686.             //if (!inscript) {  // sinon on est dans un obj.write("..
  687.             if ((intag_start_valid) && 
  688.               (
  689.               check_tag(intag_start,"script")
  690.               ||
  691.               check_tag(intag_start,"style")
  692.               )
  693.               ) {
  694.               char* a=intag_start;    // <
  695.               // ** while(is_realspace(*(--a)));
  696.               if (*a=='<') {  // s√r que c'est un tag?
  697.                 if (check_tag(intag_start,"script"))
  698.                   inscript_name="script";
  699.                 else
  700.                   inscript_name="style";
  701.                 inscript=1;
  702.                 inscript_state_pos=INSCRIPT_START;
  703.                 intag=1;     // because aprΦs <script> on y est .. - pas utile
  704.                 intag_start_valid=0;    // OUI car nous sommes dans du code, plus dans du "vrai" tag
  705.               }
  706.             }
  707.           } else {                               /* end of comment? */
  708.             // vΘrifier fermeture correcte
  709.             if ( (*(adr-1)=='-') && (*(adr-2)=='-') ) {
  710.               intag=0;
  711.               incomment=0;
  712.               intag_start_valid=0;
  713.             }
  714. #if GT_ENDS_COMMENT
  715.             /* wrong comment ending */
  716.             else {
  717.             /* check if correct ending does not exists
  718.             <!-- foo > example <!-- bar > is sometimes accepted by browsers
  719.             when no --> is used somewhere else.. darn those browsers are dirty
  720.               */
  721.               if (!strstr(adr,"-->")) {
  722.                 intag=0;
  723.                 incomment=0;
  724.                 intag_start_valid=0;
  725.               }
  726.             }
  727. #endif
  728.           }
  729.           //}
  730.         }
  731.         //else if (*adr==34) {
  732.         //  inquote=(inquote?0:1);
  733.         //}
  734.         else if (intag || inscript) {    // nous sommes dans un tag/commentaire, tester si on recoit un tag
  735.           int p_type=0;
  736.           int p_nocatch=0;
  737.           int p_searchMETAURL=0;  // chercher ..URL=<url>
  738.           int add_class=0;        // ajouter .class
  739.           int add_class_dots_to_patch=0;   // number of '.' in code="x.y.z<realname>"
  740.           char* p_flush=NULL;
  741.           
  742.           
  743.           // ------------------------------------------------------------
  744.           // parsing ΘvolΘ
  745.           // ------------------------------------------------------------
  746.           if (((isalpha((unsigned char)*adr)) || (*adr=='/') || (inscript) || (inscriptgen))) {  // sinon pas la peine de tester..
  747.             
  748.             
  749.                                                                                                  /* caractΦre de terminaison pour "miniparsing" javascript=.. ? 
  750.             (ex: <a href="javascript:()" action="foo"> ) */
  751.             if (inscript_tag) {
  752.               if (inscript_tag_lastc) {
  753.                 if (*adr == inscript_tag_lastc) {
  754.                   /* sortir */
  755.                   inscript_tag=inscript=0;
  756.                   incomment=0;
  757.                 }
  758.               }
  759.             }
  760.  
  761.             /* automate */
  762.             if (inscript) {
  763.               int new_state_pos;
  764.               new_state_pos=inscript_state[inscript_state_pos][(unsigned char)*adr];
  765.               if (new_state_pos < 0) {
  766.                 new_state_pos=inscript_state[inscript_state_pos][INSCRIPT_DEFAULT];
  767.               }
  768.               assertf(new_state_pos >= 0);
  769.               assertf(new_state_pos*sizeof(inscript_state[0]) < sizeof(inscript_state));
  770.               inscript_state_pos=new_state_pos;
  771.             }
  772.             
  773.             
  774.             // Note:
  775.             // Certaines pages ne respectent pas le html
  776.             // notamment les guillements ne sont pas fixΘs
  777.             // Nous sommes dans un tag, donc on peut faire un test plus
  778.             // large pour pouvoi prendre en compte ces particularitΘs
  779.             
  780.             // α vΘrifier: ACTION, CODEBASE, VRML
  781.             
  782.             if (in_media) {
  783.               if (strcmp(in_media,"RAM")==0) { // real media
  784.                 p=0;
  785.                 valid_p=1;
  786.               }
  787.             } else if (ptr>0) {        /* pas premiΦre page 0 (primary) */
  788.               p=0;  // saut pour le nom de fichier: adresse nom fichier=adr+p
  789.               
  790.               // ------------------------------
  791.               // dΘtection d'Θcriture JavaScript.
  792.               // osons les obj.write et les obj.href=.. ! osons!
  793.               // note: inscript==1 donc on sautera aprΦs les \"
  794.               if (inscript) {
  795.                 if (inscriptgen) {          // on est dΘja dans un objet gΘnΘrant..
  796.                   if (*adr==scriptgen_q) {  // fermeture des " ou '
  797.                     if (*(adr-1)!='\\') {   // non
  798.                       inscriptgen=0;        // ok parsing terminΘ
  799.                     }
  800.                   }
  801.                 } else {
  802.                   char* a=NULL;
  803.                   char check_this_fking_line=0;  // parsing code javascript..
  804.                   char must_be_terminated=0;     // caractΦre obligatoire de terminaison!
  805.                   int token_size;
  806.                   if (!(token_size=strfield(adr,".writeln"))) // dΘtection ...objet.write[ln]("code html")...
  807.                     token_size=strfield(adr,".write");
  808.                   if (token_size) {
  809.                     a=adr+token_size;
  810.                     while(is_realspace(*a)) a++; // sauter espaces
  811.                     if (*a=='(') {  // dΘbut parenthΦse
  812.                       check_this_fking_line=2;  // α parser!
  813.                       must_be_terminated=')';
  814.                       a++;  // sauter (
  815.                     }
  816.                   }
  817.                   // euhh ??? ???
  818.                   /* else if (strfield(adr,".href")) {  // dΘtection ...objet.href="...
  819.                   a=adr+5;
  820.                   while(is_realspace(*a)) a++; // sauter espaces
  821.                   if (*a=='=') {  // ohh un Θgal
  822.                   check_this_fking_line=1;  // α noter!
  823.                   must_be_terminated=';';   // et si t'as oubliΘ le ; tu sais pas coder
  824.                   a++;   // sauter =
  825.                   }
  826.                   
  827.                 }*/
  828.                   
  829.                   // on a un truc du genre instruction"code gΘnΘrΘ" dont on parse le code
  830.                   if (check_this_fking_line) {
  831.                     while(is_realspace(*a)) a++;
  832.                     if ((*a=='\'') || (*a=='"')) {  // dΘpart de '' ou ""
  833.                       char *b;
  834.                       int ex=0;
  835.                       scriptgen_q=*a;    // quote
  836.                       b=a+1;      // dΘpart de la chaεne
  837.                       // vΘrifier forme ("code") et pas ("code"+var), ingΘrable
  838.                       do {
  839.                         a++;  // caractΦre suivant
  840.                         if (*a==scriptgen_q && *(a-1)!='\\')  // quote non slash
  841.                           ex=1;            // sortie
  842.                         if (*a==10 && *(a-1) != '\\'  /* LF and no continue (\) character */
  843.                             && ( *(a-1) != '\r' || *(a-2) != '\\' ) )  /* and not CRLF and no .. */
  844.                           ex=1;
  845.                       } while(!ex);
  846.                       if (*a==scriptgen_q) {  // fin du quote
  847.                         a++;
  848.                         while(is_realspace(*a)) a++;
  849.                         if (*a==must_be_terminated) {  // parenthΦse fermante: ("..")
  850.                           
  851.                           // bon, on doit parser une ligne javascript
  852.                           // 1) si check.. ==1 alors c'est un nom de fichier direct, donc
  853.                           // on fixe p sur le saut nΘcessaire pour atteindre le nom du fichier
  854.                           // et le moteur se dΘbrouillera ensuite tout seul comme un grand
  855.                           // 2) si check==2 c'est un peu plus tordu car lα on gΘnΘre du
  856.                           // code html au sein de code javascript au sein de code html
  857.                           // dans ce cas on doit fixer un flag α un puis ensuite dans la boucle
  858.                           // on devra parser les instructions standard comme <a href etc
  859.                           // NOTE: le code javascript autogΘnΘrΘ n'est pas pris en compte!!
  860.                           // (et ne marche pas dans 50% des cas de toute facon!)
  861.                           if (check_this_fking_line==1) {
  862.                             p=(int) (b - adr);    // calculer saut!
  863.                           } else {
  864.                             inscriptgen=1;        // SCRIPTGEN actif
  865.                             adr=b;                // jump
  866.                           }
  867.                           
  868.                           if ((opt->debug>1) && (opt->log!=NULL)) {
  869.                             char str[512];
  870.                             str[0]='\0';
  871.                             strncatbuff(str,b,minimum((int) (a - b + 1), 32));
  872.                             fspc(opt->log,"debug"); fprintf(opt->log,"active code (%s) detected in javascript: %s"LF,(check_this_fking_line==2)?"parse":"pickup",str); test_flush;
  873.                           }
  874.                         }
  875.                         
  876.                       }
  877.                       
  878.                     }
  879.                     
  880.                     
  881.                   }
  882.                 }
  883.               }
  884.               // fin detection code gΘnΘrant javascript vers html
  885.               // ------------------------------
  886.               
  887.               
  888.               // analyse proprement dite, A HREF=.. etc..
  889.               if (!p) {
  890.                 // si dans un tag, et pas dans un script - sauf si on analyse un obj.write("..
  891.                 if ((intag && (!inscript)) || inscriptgen) {
  892.                   if ( (*(adr-1)=='<') || (is_space(*(adr-1))) ) {   // <tag < tag etc
  893.                     // <A HREF=.. pour les liens HTML
  894.                     p=rech_tageq(adr,"href");
  895.                     if (p) {    // href.. tester si c'est une bas href!
  896.                       if ((intag_start_valid) && check_tag(intag_start,"base")) {  // oui!
  897.                         // ** note: base href et codebase ne font pas bon mΘnage..
  898.                         p_type=2;    // c'est un chemin
  899.                       }
  900.                     }
  901.                     
  902.                     /* Tags supplΘmentaires α vΘrifier (<img src=..> etc) */
  903.                     if (p==0) {
  904.                       int i=0;
  905.                       while( (p==0) && (strnotempty(hts_detect[i])) ) {
  906.                         p=rech_tageq(adr,hts_detect[i]);
  907.                         if (p) {
  908.                           /* This is a temporary hack to avoid archive=foo.jar,bar.jar .. */
  909.                           if (strcmp(hts_detect[i], "archive") == 0) {
  910.                             archivetag_p = 1;
  911.                           }
  912.                         }
  913.                         i++;
  914.                       }
  915.                     }
  916.                     
  917.                     /* Tags supplΘmentaires en dΘbut α vΘrifier (<object .. hotspot1=..> etc) */
  918.                     if (p==0) {
  919.                       int i=0;
  920.                       while( (p==0) && (strnotempty(hts_detectbeg[i])) ) {
  921.                         p=rech_tageqbegdigits(adr,hts_detectbeg[i]);
  922.                         i++;
  923.                       }
  924.                     }
  925.                     
  926.                     /* Tags supplΘmentaires α vΘrifier : URL=.. */
  927.                     if (p==0) {
  928.                       int i=0;
  929.                       while( (p==0) && (strnotempty(hts_detectURL[i])) ) {
  930.                         p=rech_tageq(adr,hts_detectURL[i]);
  931.                         i++;
  932.                       }
  933.                       if (p)
  934.                         p_searchMETAURL=1;
  935.                     }
  936.                     
  937.                     /* Tags supplΘmentaires α vΘrifier, mais α ne pas capturer */
  938.                     if (p==0) {
  939.                       int i=0;
  940.                       while( (p==0) && (strnotempty(hts_detectandleave[i])) ) {
  941.                         p=rech_tageq(adr,hts_detectandleave[i]);
  942.                         i++;
  943.                       }
  944.                       if (p)
  945.                         p_nocatch=1;      /* ne pas rechercher */
  946.                     }
  947.                     
  948.                     /* EvΘnements */
  949.                     if (p==0 && 
  950.                       ! inscript          /* we don't want events inside document.write */
  951.                       ) {
  952.                       int i=0;
  953.                       /* dΘtection onLoad etc */
  954.                       while( (p==0) && (strnotempty(hts_detect_js[i])) ) {
  955.                         p=rech_tageq(adr,hts_detect_js[i]);
  956.                         i++;
  957.                       }
  958.                       /* non dΘtectΘ - dΘtecter Θgalement les onXxxxx= */
  959.                       if (p==0) {
  960.                         if ( (*adr=='o') && (*(adr+1)=='n') && isUpperLetter(*(adr+2)) ) {
  961.                           p=0;
  962.                           while(isalpha((unsigned char)adr[p]) && (p<64) ) p++;
  963.                           if (p<64) {
  964.                             while(is_space(adr[p])) p++;
  965.                             if (adr[p]=='=')
  966.                               p++;
  967.                             else p=0;
  968.                           } else p=0;
  969.                         }
  970.                       }
  971.                       /* OK, ΘvΘnement repΘrΘ */
  972.                       if (p) {
  973.                         inscript_tag_lastc=*(adr+p);     /* α attendre α la fin */
  974.                         adr+=p+1;   /* saut */
  975.                                     /*
  976.                                     On est dΘsormais dans du code javascript
  977.                         */
  978.                         inscript_name="";
  979.                         inscript=inscript_tag=1;
  980.                         inscript_state_pos=INSCRIPT_START;
  981.                       }
  982.                       p=0;        /* quoi qu'il arrive, ne rien dΘmarrer ici */
  983.                     }
  984.                     
  985.                     // <APPLET CODE=.. pour les applet java.. [CODEBASE (chemin..) α faire]
  986.                     if (p==0) {
  987.                       p=rech_tageq(adr,"code");
  988.                       if (p) {
  989.                         if ((intag_start_valid) && check_tag(intag_start,"applet")) {  // dans un <applet !
  990.                           p_type=-1;  // juste le nom de fichier+dossier, Θcire avant codebase 
  991.                           add_class=1;   // ajouter .class au besoin                         
  992.                           
  993.                           // vΘrifier qu'il n'y a pas de codebase APRES
  994.                           // sinon on swappe les deux.
  995.                           // pas trΦs propre mais c'est ce qu'il y a de plus simple α faire!!
  996.                           
  997.                           {
  998.                             char *a;
  999.                             a=adr;
  1000.                             while((*a) && (*a!='>') && (!rech_tageq(a,"codebase"))) a++;
  1001.                             if (rech_tageq(a,"codebase")) {  // banzai! codebase=
  1002.                               char* b;
  1003.                               b=strchr(a,'>');
  1004.                               if (b) {
  1005.                                 if (((int) (b - adr)) < 1000) {    // au total < 1Ko
  1006.                                   char tempo[HTS_URLMAXSIZE*2];
  1007.                                   tempo[0]='\0';
  1008.                                   strncatbuff(tempo,a,(int) (b - a) );
  1009.                                   strcatbuff( tempo," ");
  1010.                                   strncatbuff(tempo,adr,(int) (a - adr - 1));
  1011.                                   // Θventuellement remplire par des espaces pour avoir juste la taille
  1012.                                   while((int) strlen(tempo)<((int) (b - adr)))
  1013.                                     strcatbuff(tempo," ");
  1014.                                   // pas d'erreur?
  1015.                                   if ((int) strlen(tempo) == ((int) (b - adr) )) {
  1016.                                     strncpy(adr,tempo,strlen(tempo));   // PAS d'octet nul α la fin!
  1017.                                     p=0;    // DEVALIDER!!
  1018.                                     p_type=0;
  1019.                                     add_class=0;
  1020.                                   }
  1021.                                 }
  1022.                               }
  1023.                             }
  1024.                           }
  1025.                           
  1026.                         }
  1027.                       }
  1028.                     }
  1029.                     
  1030.                     // liens α patcher mais pas α charger (ex: codebase)
  1031.                     if (p==0) {  // note: si non chargΘ (ex: ignorer .class) patchΘ tout de mΩme
  1032.                       p=rech_tageq(adr,"codebase");
  1033.                       if (p) {
  1034.                         if ((intag_start_valid) && check_tag(intag_start,"applet")) {  // dans un <applet !
  1035.                           p_type=-2;
  1036.                         } else p=-1;   // ne plus chercher
  1037.                       }
  1038.                     }
  1039.                     
  1040.                     
  1041.                     // Meta tags pour robots
  1042.                     if (p==0) {
  1043.                       if (opt->robots) {
  1044.                         if ((intag_start_valid) && check_tag(intag_start,"meta")) {
  1045.                           if (rech_tageq(adr,"name")) {    // name=robots.txt
  1046.                             char tempo[1100];
  1047.                             char* a;
  1048.                             tempo[0]='\0';
  1049.                             a=strchr(adr,'>');
  1050. #if DEBUG_ROBOTS
  1051.                             printf("robots.txt meta tag detected\n");
  1052. #endif
  1053.                             if (a) {
  1054.                               if (((int) (a - adr)) < 999 ) {
  1055.                                 strncatbuff(tempo,adr,(int) (a - adr));
  1056.                                 if (strstrcase(tempo,"content")) {
  1057.                                   if (strstrcase(tempo,"robots")) {
  1058.                                     if (strstrcase(tempo,"nofollow")) {
  1059. #if DEBUG_ROBOTS
  1060.                                       printf("robots.txt meta tag: nofollow in %s%s\n",urladr,urlfil);
  1061. #endif
  1062.                                       nofollow=1;       // NE PLUS suivre liens dans cette page
  1063.                                       if (opt->errlog) {
  1064.                                         fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Link %s%s not scanned (follow robots meta tag)"LF,urladr,urlfil);
  1065.                                         test_flush;
  1066.                                       }
  1067.                                     }
  1068.                                   }
  1069.                                 }
  1070.                               }
  1071.                             }
  1072.                           }
  1073.                         }
  1074.                       }
  1075.                     }
  1076.                     
  1077.                     // entrΘe dans une applet javascript
  1078.                     /*if (!inscript) {  // sinon on est dans un obj.write("..
  1079.                     if (p==0)
  1080.                     if (rech_sampletag(adr,"script"))
  1081.                     if (check_tag(intag_start,"script")) {
  1082.                     inscript=1;
  1083.                     }
  1084.                         }*/
  1085.                     
  1086.                     // Ici on procΦde α une analyse du code javascript pour tenter de rΘcupΘrer
  1087.                     // certains fichiers Θvidents.
  1088.                     // C'est devenu obligatoire vu le nombre de pages qui intΦgrent
  1089.                     // des images rΘactives par exemple
  1090.                 }
  1091.               } else if (inscript) {
  1092.  
  1093. #if 0
  1094.                 /* Check // javascript comments */
  1095.                 if (*adr == 10 || *adr == 13) {
  1096.                   inscript_check_comments = 1;
  1097.                   inscript_in_comments = 0;
  1098.                 }
  1099.                 else if (inscript_check_comments) {
  1100.                   if (!is_realspace(*adr)) {
  1101.                     inscript_check_comments = 0;
  1102.                     if (adr[0] == '/' && adr[1] == '/') {
  1103.                       inscript_in_comments = 1;
  1104.                     }
  1105.                   }
  1106.                 }
  1107. #endif
  1108.  
  1109.                 /* Parse */
  1110.                 assertf(inscript_name != NULL);
  1111.                 if (
  1112.                   (
  1113.                   (strfield(adr,"/script") && strfield(inscript_name, "script"))
  1114.                   ||
  1115.                   (strfield(adr,"/style")  && strfield(inscript_name, "style"))
  1116.                   )
  1117.                   ) {
  1118.                   char* a=adr;
  1119.                   //while(is_realspace(*(--a)));
  1120.                   while( is_realspace(*a) ) a--;
  1121.                   a--;
  1122.                   if (*a=='<') {  // s√r que c'est un tag?
  1123.                     inscript=0;
  1124.                   }
  1125.                 } else if (inscript_state_pos == INSCRIPT_START /*!inscript_in_comments*/) {
  1126.                 /*
  1127.                 Script Analyzing - different types supported:
  1128.                 foo="url"
  1129.                 foo("url") or foo(url)
  1130.                 foo "url"
  1131.                   */
  1132.                   int nc;
  1133.                   char  expected     = '=';          // caractΦre attendu aprΦs
  1134.                   char* expected_end = ";";
  1135.                   int can_avoid_quotes=0;
  1136.                   char quotes_replacement='\0';
  1137.                   int ensure_not_mime=0;
  1138.                   if (inscript_tag)
  1139.                     expected_end=";\"\'";            // voir a href="javascript:doc.location='foo'"
  1140.                   nc = strfield(adr,".src");  // nom.src="image";
  1141.                   if (!nc) nc = strfield(adr,".location");  // document.location="doc"
  1142.                   if (!nc) nc = strfield(adr,":location");  // javascript:location="doc"
  1143.                   if (!nc) nc = strfield(adr,".href");  // document.location="doc"
  1144.                   if (!nc) if ( (nc = strfield(adr,".open")) ) { // window.open("doc",..
  1145.                     expected='(';    // parenthΦse
  1146.                     expected_end="),";  // fin: virgule ou parenthΦse
  1147.                     ensure_not_mime=1;  //* ensure the url is not a mime type */
  1148.                   }
  1149.                   if (!nc) if ( (nc = strfield(adr,".replace")) ) { // window.replace("url")
  1150.                     expected='(';    // parenthΦse
  1151.                     expected_end=")";  // fin: parenthΦse
  1152.                   }
  1153.                   if (!nc) if ( (nc = strfield(adr,".link")) ) { // window.link("url")
  1154.                     expected='(';    // parenthΦse
  1155.                     expected_end=")";  // fin: parenthΦse
  1156.                   }
  1157.                   if (!nc) if ( (nc = strfield(adr,"url")) && (!isalnum(*(adr - 1))) 
  1158.                                                            && *(adr - 1) != '_'
  1159.                                                            ) { // url(url)
  1160.                     expected='(';    // parenthΦse
  1161.                     expected_end=")";  // fin: parenthΦse
  1162.                     can_avoid_quotes=1;
  1163.                     quotes_replacement=')';
  1164.                   }
  1165.                   if (!nc) if ( (nc = strfield(adr,"import")) ) { // import "url"
  1166.                     if (is_space(*(adr+nc))) {
  1167.                       expected=0;    // no char expected
  1168.                     } else
  1169.                       nc=0;
  1170.                   }
  1171.                   if (nc) {
  1172.                     char *a;
  1173.                     a=adr+nc;
  1174.                     while(is_realspace(*a)) a++;
  1175.                     if ((*a == expected) || (!expected)) {
  1176.                       if (expected)
  1177.                         a++;
  1178.                       while(is_realspace(*a)) a++;
  1179.                       if ((*a==34) || (*a=='\'') || (can_avoid_quotes)) {
  1180.                         char *b,*c;
  1181.                         int ndelim=1;
  1182.                         if ((*a==34) || (*a=='\''))
  1183.                           a++;
  1184.                         else
  1185.                           ndelim=0;
  1186.                         b=a;
  1187.                         if (ndelim) {
  1188.                           while((*b!=34) && (*b!='\'') && (*b!='\0')) b++;
  1189.                         }
  1190.                         else {
  1191.                           while((*b != quotes_replacement) && (*b!='\0')) b++;
  1192.                         }
  1193.                         c=b--; c+=ndelim;
  1194.                         while(*c==' ') c++;
  1195.                         if ((strchr(expected_end,*c)) || (*c=='\n') || (*c=='\r')) {
  1196.                           c-=(ndelim+1);
  1197.                           if ((int) (c - a + 1)) {
  1198.                             if (ensure_not_mime) {
  1199.                               int i = 0;
  1200.                               while(a != NULL && hts_main_mime[i] != NULL && hts_main_mime[i][0] != '\0') {
  1201.                                 int p;
  1202.                                 if ((p=strfield(a, hts_main_mime[i])) && a[p] == '/') {
  1203.                                   a=NULL;
  1204.                                 }
  1205.                                 i++;
  1206.                               }
  1207.                             }
  1208.                             if (a != NULL) {
  1209.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  1210.                                 char str[512];
  1211.                                 str[0]='\0';
  1212.                                 strncatbuff(str,a,minimum((int) (c - a + 1),32));
  1213.                                 fspc(opt->log,"debug"); fprintf(opt->log,"link detected in javascript: %s"LF,str); test_flush;
  1214.                               }
  1215.                               p=(int) (a - adr);    // p non nul: TRAITER CHAINE COMME FICHIER
  1216.                               if (can_avoid_quotes) {
  1217.                                 ending_p=quotes_replacement;
  1218.                               }
  1219.                             }
  1220.                           }
  1221.                         }
  1222.                         
  1223.                         
  1224.                       }
  1225.                     }
  1226.                   }
  1227.                   
  1228.                 }
  1229.               }
  1230.             }
  1231.             
  1232.           } else {      // ptr == 0
  1233.             //p=rech_tageq(adr,"primary");    // lien primaire, yeah
  1234.             p=0;          // No stupid tag anymore, raw link
  1235.             valid_p=1;    // Valid even if p==0
  1236.             while ((adr[p] == '\r') || (adr[p] == '\n'))
  1237.               p++;
  1238.             //can_avoid_quotes=1;
  1239.             ending_p='\r';
  1240.           }       
  1241.           
  1242.         } else if (isspace((unsigned char)*adr)) {
  1243.           intag_startattr=adr+1;        // attribute in tag (for dirty parsing)
  1244.         }
  1245.         
  1246.         
  1247.         // ------------------------------------------------------------
  1248.         // dernier recours - parsing "sale" : dΘtection systΘmatique des .gif, etc.
  1249.         // risque: gΘnΘrer de faux fichiers parazites
  1250.         // fix: ne parse plus dans les commentaires
  1251.         // ------------------------------------------------------------
  1252.         if ( (opt->parseall) && (ptr>0) && (!in_media) /* && (!inscript_in_comments)*/ ) {   // option parsing "brut"
  1253.           //int incomment_justquit=0;
  1254.           if (!is_realspace(*adr)) {
  1255.             int noparse=0;
  1256.             
  1257.             // Gestion des /* */
  1258. #if 0
  1259.             if (inscript) {
  1260.               if (parseall_incomment) {
  1261.                 if ((*adr=='/') && (*(adr-1)=='*'))
  1262.                   parseall_incomment=0;
  1263.                 incomment_justquit=1;       // ne pas noter dernier caractΦre
  1264.               } else {
  1265.                 if ((*adr=='/') && (*(adr+1)=='*'))
  1266.                   parseall_incomment=1;
  1267.               }
  1268.             } else
  1269.               parseall_incomment=0;
  1270. #endif
  1271.             /* ensure automate state  0 (not in comments, quotes..) */
  1272.             if (inscript && ( 
  1273.               inscript_state_pos != INSCRIPT_INQUOTE && inscript_state_pos != INSCRIPT_INQUOTE2
  1274.               ) ) {
  1275.               noparse=1;
  1276.             }
  1277.             
  1278.             /* vΘrifier que l'on est pas dans un <!-- --> pur */
  1279.             if ( (!intag) && (incomment) && (!inscript))
  1280.               noparse=1;        /* commentaire */
  1281.             
  1282.             // recherche d'URLs
  1283.             if (!noparse) {
  1284.             //if ((!parseall_incomment) && (!noparse)) {
  1285.               if (!p) {                   // non dΘja trouvΘ
  1286.                 if (adr != r->adr) {     // >1 caractΦre
  1287.                   // scanner les chaines
  1288.                   if ((*adr == '\"') || (*adr=='\'')) {         // "xx.gif" 'xx.gif'
  1289.                     if (strchr("=(,",parseall_lastc)) {    // exemple: a="img.gif.. (handles comments)
  1290.                       char *a=adr;
  1291.                       char stop=*adr;  // " ou '
  1292.                       int count=0;
  1293.                       
  1294.                       // sauter caractΦres
  1295.                       a++;
  1296.                       // copier
  1297.                       while((*a) && (*a!='\'') && (*a!='\"') && (count<HTS_URLMAXSIZE)) { count++; a++; }
  1298.                       
  1299.                       // ok chaine terminΘe par " ou '
  1300.                       if ((*a == stop) && (count<HTS_URLMAXSIZE) && (count>0)) {
  1301.                         char c;
  1302.                         char* aend;
  1303.                         //
  1304.                         aend=a;     // sauver dΘbut
  1305.                         a++;
  1306.                         while(is_taborspace(*a)) a++;
  1307.                         c=*a;
  1308.                         if (strchr("),;>/+\r\n",c)) {     // exemple: ..img.gif";
  1309.                           // le / est pour funct("img.gif" /* URL */);
  1310.                           char tempo[HTS_URLMAXSIZE*2];
  1311.                           char type[256];
  1312.                           int url_ok=0;      // url valide?
  1313.                           tempo[0]='\0'; type[0]='\0';
  1314.                           //
  1315.                           strncatbuff(tempo,adr+1,count);
  1316.                           //
  1317.                           if ((!strchr(tempo,' ')) || inscript) {   // espace dedans: mΘfiance! (sauf dans code javascript)
  1318.                             int invalid_url=0;
  1319.                             
  1320.                             // escape                              
  1321.                             unescape_amp(tempo);
  1322.                             
  1323.                             // Couper au # ou ? Θventuel
  1324.                             {
  1325.                               char* a=strchr(tempo,'#');
  1326.                               if (a)
  1327.                                 *a='\0';
  1328.                               a=strchr(tempo,'?');
  1329.                               if (a)
  1330.                                 *a='\0';
  1331.                             }
  1332.                             
  1333.                             // vΘrifier qu'il n'y a pas de caractΦres spΘciaux
  1334.                             if (!strnotempty(tempo))
  1335.                               invalid_url=1;
  1336.                             else if (strchr(tempo,'*')
  1337.                               || strchr(tempo,'<')
  1338.                               || strchr(tempo,'>')
  1339.                               || strchr(tempo,',')    /* list of files ? */
  1340.                               || strchr(tempo,'\"')    /* potential parsing bug */
  1341.                               || strchr(tempo,'\'')    /* potential parsing bug */
  1342.                               )
  1343.                               invalid_url=1;
  1344.                             else if (tempo[0] == '.' && isalnum(tempo[1]))   // ".gif"
  1345.                               invalid_url=1;
  1346.                             
  1347.                             /* non invalide? */
  1348.                             if (!invalid_url) {
  1349.                               // Un plus α la fin? Alors ne pas prendre sauf si extension ("/toto.html#"+tag)
  1350.                               if (c!='+') {    // PAS de plus α la fin
  1351. #if 0
  1352.                                 char* a;
  1353. #endif
  1354.                                 // "Comparisons of scheme names MUST be case-insensitive" (RFC2616)                                  
  1355.                                 //if ((strncmp(tempo,"http://",7)==0) || (strncmp(tempo,"ftp://",6)==0))  // ok pas de problΦme
  1356.                                 if (
  1357.                                   (strfield(tempo,"http:")) 
  1358.                                   || (strfield(tempo,"ftp:"))
  1359. #if HTS_USEOPENSSL
  1360.                                   || (
  1361.                                   SSL_is_available &&
  1362.                                   (strfield(tempo,"https:"))
  1363.                                   )
  1364. #endif
  1365.                                   )  // ok pas de problΦme
  1366.                                   url_ok=1;
  1367.                                 else if (tempo[strlen(tempo)-1]=='/') {        // un slash: ok..
  1368.                                   if (inscript)   // sinon si pas javascript, mΘfiance (rΘpertoire style base?)
  1369.                                     url_ok=1;
  1370.                                 } 
  1371. #if 0
  1372.                                 else if ((a=strchr(tempo,'/'))) {        // un slash: ok..
  1373.                                   if (inscript) {    // sinon si pas javascript, mΘfiance (style "text/css")
  1374.                                     if (strchr(a+1,'/'))     // un seul / : abandon (STYLE type='text/css')
  1375.                                     if (!strchr(tempo,' '))  // avoid spaces (too dangerous for comments)
  1376.                                       url_ok=1;
  1377.                                   }
  1378.                                 }
  1379. #endif
  1380.                               }
  1381.                               // Prendre si extension reconnue
  1382.                               if (!url_ok) {
  1383.                                 get_httptype(type,tempo,0);
  1384.                                 if (strnotempty(type))     // type reconnu!
  1385.                                   url_ok=1;
  1386.                                 else if (is_dyntype(get_ext(tempo)))  // reconnu php,cgi,asp..
  1387.                                   url_ok=1;
  1388.                                 // MAIS pas les foobar@aol.com !!
  1389.                                 if (strchr(tempo,'@'))
  1390.                                   url_ok=0;
  1391.                               }
  1392.                               //
  1393.                               // Ok, cela pourrait Ωtre une URL
  1394.                               if (url_ok) {
  1395.                                 
  1396.                                 // Check if not fodbidden tag (id,name..)
  1397.                                 if (intag_start_valid) {
  1398.                                   if (intag_start)
  1399.                                     if (intag_startattr)
  1400.                                       if (intag)
  1401.                                         if (!inscript)
  1402.                                           if (!incomment) {
  1403.                                             int i=0,nop=0;
  1404.                                             while( (nop==0) && (strnotempty(hts_nodetect[i])) ) {
  1405.                                               nop=rech_tageq(intag_startattr,hts_nodetect[i]);
  1406.                                               i++;
  1407.                                             }
  1408.                                             // Forbidden tag
  1409.                                             if (nop) {
  1410.                                               url_ok=0;
  1411.                                               if ((opt->debug>1) && (opt->log!=NULL)) {
  1412.                                                 fspc(opt->log,"debug"); fprintf(opt->log,"dirty parsing: bad tag avoided: %s"LF,hts_nodetect[i-1]); test_flush;
  1413.                                               }
  1414.                                             }
  1415.                                           }
  1416.                                 }
  1417.                                 
  1418.                                 
  1419.                                 // Accepter URL, on la traitera comme une URL normale!!
  1420.                                 if (url_ok) {
  1421.                                   valid_p = 1;
  1422.                                   p = 0;
  1423.                                 }
  1424.                                 
  1425.                               }
  1426.                             }
  1427.                           }
  1428.                           }
  1429.                         }
  1430.                       }
  1431.                     }
  1432.                   }
  1433.                 }  // p == 0               
  1434.                 
  1435.               } // not in comment
  1436.               
  1437.               // plus dans un commentaire
  1438.               if ( inscript_state_pos == INSCRIPT_START 
  1439.                 && inscript_state_pos_prev == INSCRIPT_START) {
  1440.                 parseall_lastc=*adr;             // caractΦre avant le prochain
  1441.               }
  1442.  
  1443.  
  1444.             }  // if realspace
  1445.           }  // if parseall
  1446.           
  1447.           
  1448.           // ------------------------------------------------------------
  1449.           // p!=0 : on a repΘrΘ un Θventuel lien
  1450.           // ------------------------------------------------------------
  1451.           //
  1452.           if ((p>0) || (valid_p)) {    // on a repΘrΘ un lien
  1453.             //int lien_valide=0;
  1454.             char* eadr=NULL;          /* fin de l'URL */
  1455.             char* quote_adr=NULL;     /* adresse du ? dans l'adresse */
  1456.             int ok=1;
  1457.             char quote='\0';
  1458.             int quoteinscript=0;
  1459.             int  noquote=0;
  1460.             
  1461.             // si nofollow ou un stop a ΘtΘ dΘclenchΘ, rΘΘcrire tous les liens en externe
  1462.             if ((nofollow) || (opt->state.stop))
  1463.               p_nocatch=1;
  1464.             
  1465.             // Θcrire codebase avant, flusher avant code
  1466.             if ((p_type==-1) || (p_type==-2)) {
  1467.               if ((opt->getmode & 1) && (ptr>0)) {
  1468.                 HT_ADD_ADR;    // refresh
  1469.               }
  1470.               lastsaved=adr;    // dernier Θcrit+1
  1471.             }
  1472.             
  1473.             // sauter espaces
  1474.             adr+=p;
  1475.             while( ( is_space(*adr) || (
  1476.                                         inscriptgen 
  1477.                                         && adr[0] == '\\' 
  1478.                                         && is_space(adr[1])
  1479.                                        )
  1480.                    )
  1481.                    && quote == '\0'
  1482.                  ) {
  1483.               if (!quote)
  1484.                 if ((*adr=='\"') || (*adr=='\'')) {
  1485.                   quote=*adr;                     // on doit attendre cela α la fin
  1486.                   if (inscriptgen && *(adr - 1) == '\\') {
  1487.                     quoteinscript=1;  /* will wait for \" */
  1488.                   }
  1489.                 }
  1490.                 // puis quitter
  1491.                 adr++;    // sauter les espaces, "" et cie
  1492.             }
  1493.             
  1494.             /* Stop at \n (LF) if primary links*/
  1495.             if (ptr == 0)
  1496.               quote='\n';
  1497.             /* s'arrΩter que ce soit un ' ou un " : pour document.write('<img src="foo'+a); par exemple! */
  1498.             else if (inscript)
  1499.               noquote=1;
  1500.             
  1501.             // sauter Θventuel \" ou \' javascript
  1502.             if (inscript) {    // on est dans un obj.write("..
  1503.               if (*adr=='\\') {
  1504.                 if ((*(adr+1)=='\'') || (*(adr+1)=='"')) {  // \" ou \'
  1505.                   adr+=2;    // sauter
  1506.                 }
  1507.               }
  1508.             }
  1509.             
  1510.             // sauter content="1;URL=http://..
  1511.             if (p_searchMETAURL) {
  1512.               int l=0;
  1513.               while(
  1514.                 (adr + l + 4 < r->adr + r->size)
  1515.                 && (!strfield(adr+l,"URL=")) 
  1516.                 && (l<128) ) l++;
  1517.               if (!strfield(adr+l,"URL="))
  1518.                 ok=-1;
  1519.               else
  1520.                 adr+=(l+4);
  1521.             }
  1522.             
  1523.             /* Θviter les javascript:document.location=.. : les parser, plut⌠t */
  1524.             if (ok!=-1) {
  1525.               if (strfield(adr,"javascript:") 
  1526.                 && ! inscript       /* we don't want to parse 'javascript:' inside document.write inside scripts */
  1527.                 ) {
  1528.                 ok=-1;
  1529.                 /*
  1530.                 On est dΘsormais dans du code javascript
  1531.                 */
  1532.                 inscript_name="";
  1533.                 inscript_tag=inscript=1;
  1534.                 inscript_state_pos=INSCRIPT_START;
  1535.                 inscript_tag_lastc=quote;     /* α attendre α la fin */
  1536.               }
  1537.             }
  1538.             
  1539.             if (p_type==1) {
  1540.               if (*adr=='#') {
  1541.                 adr++;           // sauter # pour usemap etc
  1542.               }
  1543.             }
  1544.             eadr=adr;
  1545.             
  1546.             // ne pas flusher aprΦs code si on doit Θcrire le codebase avant!
  1547.             if ((p_type!=-1) && (p_type!=2) && (p_type!=-2)) {
  1548.               if ((opt->getmode & 1) && (ptr>0)) {
  1549.                 HT_ADD_ADR;    // refresh
  1550.               }
  1551.               lastsaved=adr;    // dernier Θcrit+1
  1552.               // aprΦs on Θcrira soit les donnΘes initiales,
  1553.               // soir une URL/lien modifiΘ!
  1554.             } else if (p_type==-1) p_flush=adr;    // flusher jusqu'α adr ensuite
  1555.             
  1556.             if (ok!=-1) {    // continuer
  1557.               // dΘcouper le lien
  1558.               do {
  1559.                 if ((* (unsigned char*) eadr)<32) {   // caractΦre de contr⌠le (ou \0)
  1560.                   if (!is_space(*eadr))
  1561.                     ok=0; 
  1562.                 }
  1563.                 if ( ( ((int) (eadr - adr)) ) > HTS_URLMAXSIZE)  // ** trop long, >HTS_URLMAXSIZE caractΦres (on prΘvoit HTS_URLMAXSIZE autres pour path)
  1564.                   ok=-1;    // ne pas traiter ce lien
  1565.                 
  1566.                 if (ok > 0) {
  1567.                   //if (*eadr!=' ') {  
  1568.                   if (is_space(*eadr)) {   // guillemets,CR, etc
  1569.                     if ( 
  1570.                             ( *eadr == quote && ( !quoteinscript || *(eadr -1) == '\\') )  // end quote
  1571.                          || ( noquote && (*eadr == '\"' || *eadr == '\'') )       // end at any quote
  1572.                          || (!noquote && quote == '\0' && is_realspace(*eadr) )   // unquoted href
  1573.                        )     // si pas d'attente de quote spΘciale ou si quote atteinte
  1574.                       ok=0; 
  1575.                   } else if (ending_p && (*eadr==ending_p))
  1576.                     ok=0;
  1577.                   else {
  1578.                     switch(*eadr) {
  1579.                     case '>': 
  1580.                       if (!quote) {
  1581.                         if (!inscript) {
  1582.                           intag=0;    // PLUS dans un tag!
  1583.                           intag_start_valid=0;
  1584.                         }
  1585.                         ok=0;
  1586.                       }
  1587.                       break;
  1588.                       /*case '<':*/ 
  1589.                     case '#': 
  1590.                       if (*(eadr-1) != '&')       // (
  1591.                         ok=0; 
  1592.                       break;
  1593.                       // case '?': non!
  1594.                     case '\\': if (inscript) ok=0; break;     // \" ou \' point d'arrΩt
  1595.                     case '?': quote_adr=adr; break;           // noter position query
  1596.                     }
  1597.                   }
  1598.                   //}
  1599.                 } 
  1600.                 eadr++;
  1601.               } while(ok==1);
  1602.               
  1603.               // Empty link detected
  1604.               if ( (((int) (eadr - adr))) <= 1) {       // link empty
  1605.                 ok=-1;        // No
  1606.                 if (*adr != '#') {        // Not empty+unique #
  1607.                   if ( (((int) (eadr - adr)) == 1)) {       // 1=link empty with delim (end_adr-start_adr)
  1608.                     if (quote) {
  1609.                       if ((opt->getmode & 1) && (ptr>0)) { 
  1610.                         HT_ADD("#");        // We add this for a <href="">
  1611.                       }
  1612.                     }
  1613.                   }
  1614.                 }
  1615.               }
  1616.  
  1617.               // This is a dirty and horrible hack to avoid parsing an Adobe GoLive bogus tag
  1618.               if (strfield(adr, "(Empty Reference!)")) {
  1619.                 ok=-1;        // No
  1620.               }
  1621.               
  1622.             }
  1623.             
  1624.             if (ok==0) {    // tester un lien
  1625.               char lien[HTS_URLMAXSIZE*2];
  1626.               int meme_adresse=0;      // 0 par dΘfaut pour primary
  1627.               //char *copie_de_adr=adr;
  1628.               //char* p;
  1629.               
  1630.               // construire lien (dΘcoupage)
  1631.               if ( (((int) (eadr -  adr))-1) < HTS_URLMAXSIZE  ) {    // pas trop long?
  1632.                 strncpy(lien,adr,((int) (eadr - adr))-1);
  1633.                 *(lien+  (((int) (eadr -  adr)))-1  )='\0';
  1634.                 //printf("link: %s\n",lien);          
  1635.                 // supprimer les espaces
  1636.                 while((lien[strlen(lien)-1]==' ') && (strnotempty(lien))) lien[strlen(lien)-1]='\0';
  1637.                 
  1638.                 
  1639. #if HTS_STRIP_DOUBLE_SLASH
  1640.                 // supprimer les // en / (sauf pour http://)
  1641.                 {
  1642.                   char *a,*p,*q;
  1643.                   int done=0;
  1644.                   a=strchr(lien,':');    // http://
  1645.                   if (a) {
  1646.                     a++;
  1647.                     while(*a=='/') a++;    // position aprΦs http://
  1648.                   } else {
  1649.                     a=lien;                // dΘbut
  1650.                     while(*a=='/') a++;    // position aprΦs http://
  1651.                   }
  1652.                   q=strchr(a,'?');     // ne pas traiter aprΦs '?'
  1653.                   if (!q)
  1654.                     q=a+strlen(a)-1;
  1655.                   while(( p=strstr(a,"//")) && (!done) ) {    // remplacer // par /
  1656.                     if ((int) p>(int) q) {   // aprΦs le ? (toto.cgi?param=1//2.3)
  1657.                       done=1;    // stopper
  1658.                     } else {
  1659.                       char tempo[HTS_URLMAXSIZE*2];
  1660.                       tempo[0]='\0';
  1661.                       strncatbuff(tempo,a,(int) p - (int) a);
  1662.                       strcatbuff (tempo,p+1);
  1663.                       strcpybuff(a,tempo);    // recopier
  1664.                     }
  1665.                   }
  1666.                 }
  1667. #endif
  1668.                 
  1669.               } else
  1670.                 lien[0]='\0';    // erreur
  1671.               
  1672.               // ------------------------------------------------------
  1673.               // Lien repΘrΘ et extrait
  1674.               if (strnotempty(lien)>0) {           // construction du lien
  1675.                 char adr[HTS_URLMAXSIZE*2],fil[HTS_URLMAXSIZE*2];          // ATTENTION adr cache le "vrai" adr
  1676.                 int forbidden_url=-1;              // lien non interdit (mais non autorisΘ..)
  1677.                 int just_test_it=0;                // mode de test des liens
  1678.                 int set_prio_to=0;                 // pour capture de page isolΘe
  1679.                 int import_done=0;                 // lien importΘ (ne pas scanner ensuite *α priori*)
  1680.                 //
  1681.                 adr[0]='\0'; fil[0]='\0';
  1682.                 //
  1683.                 // 0: autorisΘ
  1684.                 // 1: interdit (patcher tout de mΩme adresse)
  1685.                 
  1686.                 if ((opt->debug>1) && (opt->log!=NULL)) {
  1687.                   fspc(opt->log,"debug"); fprintf(opt->log,"link detected in html: %s"LF,lien); test_flush;
  1688.                 }
  1689.                 
  1690.                 // external check
  1691. #if HTS_ANALYSTE
  1692.                 if (!hts_htmlcheck_linkdetected(lien)) {
  1693.                   error=1;    // erreur
  1694.                   if (opt->errlog) {
  1695.                     fspc(opt->errlog,"error"); fprintf(opt->errlog,"Link %s refused by external wrapper"LF,lien);
  1696.                     test_flush;
  1697.                   }
  1698.                 }
  1699. #endif
  1700.                 
  1701.                 // purger espaces de dΘbut et fin, CR,LF rΘsiduels
  1702.                 // (IMG SRC="foo.<\n><\t>gif<\t>")
  1703.                 {
  1704.                   char* a = lien;
  1705.                   int llen;
  1706.  
  1707.                   // strip ending spaces
  1708.                   llen = ( *a != '\0' ) ? strlen(a) : 0;
  1709.                   while(llen > 0 && is_realspace(lien[llen - 1]) ) {
  1710.                     a[--llen]='\0';
  1711.                   } 
  1712.                   //  skip leading ones
  1713.                   while(is_realspace(*a)) a++;
  1714.                   // strip cr, lf, tab inside URL
  1715.                   llen = 0;
  1716.                   while(*a) {
  1717.                     if (*a != '\n' && *a != '\r' && *a != '\t') {
  1718.                       lien[llen++] = *a;
  1719.                     }
  1720.                     a++;
  1721.                   }
  1722.                   lien[llen] = '\0';
  1723.                 }
  1724.  
  1725.                 // commas are forbidden
  1726.                 if (archivetag_p) {
  1727.                   if (strchr(lien, ',')) {
  1728.                     error=1;    // erreur
  1729.                     if ((opt->debug>1) && (opt->log!=NULL)) {
  1730.                       fspc(opt->log,"debug"); fprintf(opt->log,"link rejected (multiple-archive) %s"LF,lien); test_flush;
  1731.                     }
  1732.                   }
  1733.                 }               
  1734.                 
  1735.                 /* Unescape/escape %20 and other   */
  1736.                 {
  1737.                   char query[HTS_URLMAXSIZE*2];
  1738.                   char* a=strchr(lien,'?');
  1739.                   if (a) {
  1740.                     strcpybuff(query,a);
  1741.                     *a='\0';
  1742.                   } else
  1743.                     query[0]='\0';
  1744.                   // conversion & -> & et autres joyeusetΘs
  1745.                   unescape_amp(lien);
  1746.                   unescape_amp(query);
  1747.                   // dΘcoder l'inutile (%2E par exemple) et coder espaces
  1748.                   // XXXXXXXXXXXXXXXXX strcpybuff(lien,unescape_http(lien));
  1749.                   strcpybuff(lien,unescape_http_unharm(lien, (no_esc_utf)?0:1));
  1750.                   escape_remove_control(lien);
  1751.                   escape_spc_url(lien);
  1752.                   strcatbuff(lien,query);     /* restore */
  1753.                 }
  1754.                 
  1755.                 // convertir les Θventuels \ en des / pour Θviter des problΦmes de reconnaissance!
  1756.                 {
  1757.                   char* a=jump_identification(lien);
  1758.                   while( (a=strchr(a,'\\')) ) *a='/';
  1759.                 }
  1760.                 
  1761.                 // supprimer le(s) ./
  1762.                 while ((lien[0]=='.') && (lien[1]=='/')) {
  1763.                   char tempo[HTS_URLMAXSIZE*2];
  1764.                   strcpybuff(tempo,lien+2);
  1765.                   strcpybuff(lien,tempo);
  1766.                 }
  1767.                 if (strnotempty(lien)==0)  // sauf si plus de nom de fichier
  1768.                   strcpybuff(lien,"./");
  1769.                 
  1770.                 // vΘrifie les /~machin -> /~machin/
  1771.                 // supposition dangereuse?
  1772.                 // OUI!!
  1773. #if HTS_TILDE_SLASH
  1774.                 if (lien[strlen(lien)-1]!='/') {
  1775.                   char *a=lien+strlen(lien)-1;
  1776.                   // Θviter aussi index~1.html
  1777.                   while (((int) a>(int) lien) && (*a!='~') && (*a!='/') && (*a!='.')) a--;
  1778.                   if (*a=='~') {
  1779.                     strcatbuff(lien,"/");    // ajouter slash
  1780.                   }
  1781.                 }
  1782. #endif
  1783.                 
  1784.                 // APPLET CODE="mixer.MixerApplet.class" --> APPLET CODE="mixer/MixerApplet.class"
  1785.                 // yes, this is dirty
  1786.                 // but I'm so lazzy..
  1787.                 // and besides the java "code" convention is really a pain in html code
  1788.                 if (p_type==-1) {
  1789.                   char* a=strrchr(lien,'.');
  1790.                   add_class_dots_to_patch=0;
  1791.                   if (a) {
  1792.                     char* b;
  1793.                     do {
  1794.                       b=strchr(lien,'.');
  1795.                       if ((b != a) && (b)) {
  1796.                         add_class_dots_to_patch++;
  1797.                         *b='/';
  1798.                       }
  1799.                     } while((b != a) && (b));
  1800.                   }
  1801.                 }
  1802.  
  1803.                 // Θliminer les Θventuels :80 (port par dΘfaut!)
  1804.                 if (link_has_authority(lien)) {
  1805.                   char * a;
  1806.                   a=strstr(lien,"//");    // "//" authority
  1807.                   if (a)
  1808.                     a+=2;
  1809.                   else
  1810.                     a=lien;
  1811.                   // while((*a) && (*a!='/') && (*a!=':')) a++;
  1812.                   a=jump_toport(a);
  1813.                   if (a) {  // port
  1814.                     int port=0;
  1815.                     int defport=80;
  1816.                     char* b=a+1;
  1817. #if HTS_USEOPENSSL
  1818.                     // FIXME
  1819.                     //if (strfield(adr, "https:")) {
  1820.                     //}
  1821. #endif
  1822.                     while(isdigit((unsigned char)*b)) { port*=10; port+=(int) (*b-'0'); b++; }
  1823.                     if (port==defport) {  // port 80, default - c'est dΘbile
  1824.                       char tempo[HTS_URLMAXSIZE*2];
  1825.                       tempo[0]='\0';
  1826.                       strncatbuff(tempo,lien,(int) (a - lien));
  1827.                       strcatbuff(tempo,a+3);  // sauter :80
  1828.                       strcpybuff(lien,tempo);
  1829.                     }
  1830.                   }
  1831.                 }
  1832.                 
  1833.                 // filtrer les parazites (mailto & cie)
  1834.                 /*
  1835.                 if (strfield(lien,"mailto:")) {  // ne pas traiter
  1836.                 error=1;
  1837.                 } else if (strfield(lien,"news:")) {  // ne pas traiter
  1838.                 error=1;
  1839.                 }
  1840.                 */
  1841.                 
  1842.                 // vΘrifier que l'on ne doit pas ajouter de .class
  1843.                 if (!error) {
  1844.                   if (add_class) {
  1845.                     char *a = lien+strlen(lien)-1;
  1846.                     while(( a > lien) && (*a!='/') && (*a!='.')) a--;
  1847.                     if (*a != '.')
  1848.                       strcatbuff(lien,".class");    // ajouter .class
  1849.                     else if (!strfield2(a,".class"))
  1850.                       strcatbuff(lien,".class");    // idem
  1851.                   }
  1852.                 }
  1853.                 
  1854.                 // si c'est un chemin, alors vΘrifier (toto/toto.html -> http://www/toto/)
  1855.                 if (!error) {
  1856.                   if ((opt->debug>1) && (opt->log!=NULL)) {
  1857.                     fspc(opt->log,"debug"); fprintf(opt->log,"position link check %s"LF,lien); test_flush;
  1858.                   }
  1859.                   
  1860.                   if ((p_type==2) || (p_type==-2)) {   // code ou codebase                        
  1861.                     // VΘrifier les codebase=applet (au lieu de applet/)
  1862.                     if (p_type==-2) {    // codebase
  1863.                       if (strnotempty(lien)) {
  1864.                         if (fil[strlen(lien)-1]!='/') {  // pas rΘpertoire
  1865.                           strcatbuff(lien,"/");
  1866.                         }
  1867.                       }
  1868.                     }
  1869.  
  1870.                     /* base has always authority */
  1871.                     if (p_type==2 && !link_has_authority(lien)) {
  1872.                       char tmp[HTS_URLMAXSIZE*2];
  1873.                       strcpybuff(tmp, "http://");
  1874.                       strcatbuff(tmp, lien);
  1875.                       strcpybuff(lien, tmp);
  1876.                     }
  1877.  
  1878.                     /* only one ending / (bug on some pages) */
  1879.                     if ((int)strlen(lien)>2) {
  1880.                       int len = (int) strlen(lien);
  1881.                       while(len > 1 && lien[len-1] == '/' && lien[len-2] == '/' )    /* double // (bug) */
  1882.                         lien[--len]='\0';
  1883.                     }
  1884.                     // copier nom host si besoin est
  1885.                     if (!link_has_authority(lien)) {  // pas de http://
  1886.                       char adr2[HTS_URLMAXSIZE*2],fil2[HTS_URLMAXSIZE*2];  // ** euh ident_url_relatif??
  1887.                       if (ident_url_relatif(lien,urladr,urlfil,adr2,fil2)<0) {                        
  1888.                         error=1;
  1889.                       } else {
  1890.                         strcpybuff(lien,"http://");
  1891.                         strcatbuff(lien,adr2);
  1892.                         if (*fil2!='/')
  1893.                           strcatbuff(lien,"/");
  1894.                         strcatbuff(lien,fil2);
  1895.                         {
  1896.                           char* a;
  1897.                           a=lien+strlen(lien)-1;
  1898.                           while((*a) && (*a!='/') && ( a> lien)) a--;
  1899.                           if (*a=='/') {
  1900.                             *(a+1)='\0';
  1901.                           }
  1902.                         }
  1903.                         //char tempo[HTS_URLMAXSIZE*2];
  1904.                         //strcpybuff(tempo,"http://");
  1905.                         //strcatbuff(tempo,urladr);    // host
  1906.                         //if (*lien!='/')
  1907.                         //  strcatbuff(tempo,"/");
  1908.                         //strcatbuff(tempo,lien);
  1909.                         //strcpybuff(lien,tempo);
  1910.                       }
  1911.                     }
  1912.                     
  1913.                     if (!error) {  // pas d'erreur?
  1914.                       if (p_type==2) {   // code ET PAS codebase      
  1915.                         char* a=lien+strlen(lien)-1;
  1916.                         while( (a > lien) && (*a) && (*a!='/')) a--;
  1917.                         if (*a=='/')     // ok on a repΘrΘ le dernier /
  1918.                           *(a+1)='\0';   // couper
  1919.                         else {
  1920.                           *lien='\0';    // Θliminer
  1921.                           error=1;   // erreur, ne pas poursuivre
  1922.                         }      
  1923.                       }
  1924.                       
  1925.                       // stocker base ou codebase?
  1926.                       switch(p_type) {
  1927.                       case 2: { 
  1928.                         //if (*lien!='/') strcatbuff(base,"/");
  1929.                         strcpybuff(base,lien);
  1930.                               }
  1931.                         break;      // base
  1932.                       case -2: {
  1933.                         //if (*lien!='/') strcatbuff(codebase,"/");
  1934.                         strcpybuff(codebase,lien); 
  1935.                                }
  1936.                         break;  // base
  1937.                       }
  1938.                       
  1939.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  1940.                         fspc(opt->log,"debug"); fprintf(opt->log,"code/codebase link %s base %s"LF,lien,base); test_flush;
  1941.                       }
  1942.                       //printf("base code: %s - %s\n",lien,base);
  1943.                     }
  1944.                     
  1945.                   } else {
  1946.                     char* _base;
  1947.                     if (p_type==-1)   // code (applet)
  1948.                       _base=codebase;
  1949.                     else
  1950.                       _base=base;
  1951.                     
  1952.                     
  1953.                     // ajouter chemin de base href..
  1954.                     if (strnotempty(_base)) {       // considΘrer base
  1955.                       if (!link_has_authority(lien)) {    // non absolue
  1956.                         if (*lien!='/') {           // non absolu sur le site (/)
  1957.                           if ( ((int) strlen(_base)+(int) strlen(lien))<HTS_URLMAXSIZE) {
  1958.                             // mailto: and co: do NOT add base
  1959.                             if (ident_url_relatif(lien,urladr,urlfil,adr,fil)>=0) {
  1960.                               char tempo[HTS_URLMAXSIZE*2];
  1961.                               // base est absolue
  1962.                               strcpybuff(tempo,_base);
  1963.                               strcatbuff(tempo,lien + ((*lien=='/')?1:0) );
  1964.                               strcpybuff(lien,tempo);        // patcher en considΘrant base
  1965.                               // ** vΘrifier que ../ fonctionne (ne doit pas arriver mais bon..)
  1966.                               
  1967.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  1968.                                 fspc(opt->log,"debug"); fprintf(opt->log,"link modified with code/codebase %s"LF,lien); test_flush;
  1969.                               }
  1970.                             }
  1971.                           } else {
  1972.                             error=1;    // erreur
  1973.                             if (opt->errlog) {
  1974.                               fspc(opt->errlog,"error"); fprintf(opt->errlog,"Link %s too long with base href"LF,lien);
  1975.                               test_flush;
  1976.                             }
  1977.                           }
  1978.                         } else {
  1979.                           char badr[HTS_URLMAXSIZE*2], bfil[HTS_URLMAXSIZE*2];
  1980.                           if (ident_url_absolute(_base, badr, bfil) >=0 ) {
  1981.                             if ( ((int) strlen(badr)+(int) strlen(lien)) < HTS_URLMAXSIZE) {
  1982.                               char tempo[HTS_URLMAXSIZE*2];
  1983.                               // base est absolue
  1984.                               tempo[0] = '\0';
  1985.                               if (!link_has_authority(badr)) {
  1986.                                 strcatbuff(tempo, "http://");
  1987.                               }
  1988.                               strcatbuff(tempo,badr);
  1989.                               strcatbuff(tempo,lien);
  1990.                               strcpybuff(lien,tempo);        // patcher en considΘrant base
  1991.                               
  1992.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  1993.                                 fspc(opt->log,"debug"); fprintf(opt->log,"link modified with code/codebase %s"LF,lien); test_flush;
  1994.                               }
  1995.                             } else {
  1996.                               error=1;    // erreur
  1997.                               if (opt->errlog) {
  1998.                                 fspc(opt->errlog,"error"); fprintf(opt->errlog,"Link %s too long with base href"LF,lien);
  1999.                                 test_flush;
  2000.                               }
  2001.                             }
  2002.                           }
  2003.                         }
  2004.                       }
  2005.                     }
  2006.                     
  2007.                     
  2008.                   }
  2009.                 }
  2010.                 
  2011.                 
  2012.                 // transformer lien quelconque (http, relatif, etc) en une adresse
  2013.                 // et un chemin+fichier (adr,fil)
  2014.                 if (!error) {
  2015.                   int reponse;
  2016.                   if ((opt->debug>1) && (opt->log!=NULL)) {
  2017.                     fspc(opt->log,"debug"); fprintf(opt->log,"build relative link %s with %s%s"LF,lien,relativeurladr,relativeurlfil); test_flush;
  2018.                   }
  2019.                   if ((reponse=ident_url_relatif(lien,relativeurladr,relativeurlfil,adr,fil))<0) {                        
  2020.                     adr[0]='\0';    // erreur
  2021.                     if (reponse==-2) {
  2022.                       if (opt->errlog) {
  2023.                         fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Link %s not caught (unknown protocol)"LF,lien);
  2024.                         test_flush;
  2025.                       }
  2026.                     } else {
  2027.                       if ((opt->debug>1) && (opt->errlog!=NULL)) {
  2028.                         fspc(opt->errlog,"debug"); fprintf(opt->errlog,"ident_url_relatif failed for %s with %s%s"LF,lien,relativeurladr,relativeurlfil); test_flush;
  2029.                       }
  2030.                     }
  2031.                   } else {
  2032.                     if ((opt->debug>1) && (opt->log!=NULL)) {
  2033.                       fspc(opt->log,"debug"); fprintf(opt->log,"built relative link %s with %s%s -> %s%s"LF,lien,relativeurladr,relativeurlfil,adr,fil); test_flush;
  2034.                     }
  2035.                   }
  2036.                 } else {
  2037.                   if ((opt->debug>1) && (opt->log!=NULL)) {
  2038.                     fspc(opt->log,"debug"); fprintf(opt->log,"link %s not build, error detected before"LF,lien); test_flush;
  2039.                   }
  2040.                   adr[0]='\0';
  2041.                 }
  2042.                 
  2043. #if HTS_CHECK_STRANGEDIR
  2044.                 // !ATTENTION!
  2045.                 // Ici on teste les exotiques du genre www.truc.fr/machin (sans slash α la fin)
  2046.                 // je n'ai pas encore trouvΘ le moyen de faire la diffΘrence entre un rΘpertoire
  2047.                 // et un fichier en http A PRIORI : je fais donc un test
  2048.                 // En cas de moved xxx, on recalcule adr et fil, tout simplement
  2049.                 // DEFAUT: test effectuΘ plusieurs fois! α revoir!!!
  2050.                 if ((adr[0]!='\0') && (strcmp(adr,"file://") && (p_type!=2) && (p_type!=-2)) {
  2051.                   //## if ((adr[0]!='\0') && (adr[0]!=lOCAL_CHAR) && (p_type!=2) && (p_type!=-2)) {
  2052.                   if (fil[strlen(fil)-1]!='/') {  // pas rΘpertoire
  2053.                     if (ishtml(fil)==-2) {    // pas d'extension
  2054.                       char loc[HTS_URLMAXSIZE*2];  // Θventuelle nouvelle position
  2055.                       loc[0]='\0';
  2056.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  2057.                         fspc(opt->log,"debug"); fprintf(opt->log,"link-check-directory: %s%s"LF,adr,fil);
  2058.                         test_flush;
  2059.                       }
  2060.                       
  2061.                       // tester Θventuelle nouvelle position
  2062.                       switch (http_location(adr,fil,loc).statuscode) {
  2063.                       case 200: // ok au final
  2064.                         if (strnotempty(loc)) {  // a changΘ d'adresse
  2065.                           if (opt->errlog) {
  2066.                             fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Link %s%s has moved to %s for %s%s"LF,adr,fil,loc,urladr,urlfil);
  2067.                             test_flush;
  2068.                           }
  2069.                           
  2070.                           // recalculer adr et fil!
  2071.                           if (ident_url_absolute(loc,adr,fil)==-1) {
  2072.                             adr[0]='\0';  // cancel
  2073.                             if ((opt->debug>1) && (opt->log!=NULL)) {
  2074.                               fspc(opt->log,"debug"); fprintf(opt->log,"link-check-dir: %s%s"LF,adr,fil);
  2075.                               test_flush;
  2076.                             }
  2077.                           }
  2078.                           
  2079.                         }
  2080.                         break;
  2081.                       case -2: case -3:  // timeout ou erreur grave
  2082.                         if (opt->errlog) {
  2083.                           fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Connection too slow for testing link %s%s (from %s%s)"LF,adr,fil,urladr,urlfil);
  2084.                           test_flush;
  2085.                         }
  2086.                         
  2087.                         break;
  2088.                       }
  2089.                       
  2090.                     }
  2091.                   } 
  2092.                 }
  2093. #endif
  2094.                 
  2095.                 // Le lien doit juste Ωtre rΘΘcrit, mais ne doit pas gΘnΘrer un lien
  2096.                 // exemple: <FORM ACTION="url_cgi">
  2097.                 if (p_nocatch) {
  2098.                   forbidden_url=1;    // interdire rΘcupΘration du lien
  2099.                   if ((opt->debug>1) && (opt->log!=NULL)) {
  2100.                     fspc(opt->log,"debug"); fprintf(opt->log,"link forced external at %s%s"LF,adr,fil);
  2101.                     test_flush;
  2102.                   }
  2103.                 }
  2104.                 
  2105.                 // Tester si un lien doit Ωtre acceptΘ ou refusΘ (wizard)
  2106.                 // forbidden_url=1 : lien refusΘ
  2107.                 // forbidden_url=0 : lien acceptΘ
  2108.                 //if ((ptr>0) && (p_type!=2) && (p_type!=-2)) {    // tester autorisations?
  2109.                 if ((p_type!=2) && (p_type!=-2)) {    // tester autorisations?
  2110.                   if (!p_nocatch) {
  2111.                     if (adr[0]!='\0') {          
  2112.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  2113.                         fspc(opt->log,"debug"); fprintf(opt->log,"wizard link test at %s%s.."LF,adr,fil);
  2114.                         test_flush;
  2115.                       }
  2116.                       forbidden_url=hts_acceptlink(opt,ptr,lien_tot,liens,
  2117.                         adr,fil,
  2118.                         &set_prio_to,
  2119.                         &just_test_it);
  2120.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  2121.                         fspc(opt->log,"debug"); fprintf(opt->log,"result for wizard link test: %d"LF,forbidden_url);
  2122.                         test_flush;
  2123.                       }
  2124.                     }
  2125.                   }
  2126.                 }
  2127.                 
  2128.                 // calculer meme_adresse
  2129.                 meme_adresse=strfield2(jump_identification(adr),jump_identification(urladr));
  2130.                 
  2131.                 
  2132.                 
  2133.                 // DΘbut partie sauvegarde
  2134.                 
  2135.                 // ici on forme le nom du fichier α sauver, et on patche l'URL
  2136.                 if (adr[0]!='\0') {
  2137.                   // savename: simplifier les ../ et autres joyeusetΘs
  2138.                   char save[HTS_URLMAXSIZE*2];
  2139.                   int r_sv=0;
  2140.                   // En cas de moved, adresse premiΦre
  2141.                   char former_adr[HTS_URLMAXSIZE*2];
  2142.                   char former_fil[HTS_URLMAXSIZE*2];
  2143.                   //
  2144.                   save[0]='\0'; former_adr[0]='\0'; former_fil[0]='\0';
  2145.                   //
  2146.                   
  2147.                   // nom du chemin α sauver si on doit le calculer
  2148.                   // note: url_savename peut dΘcider de tester le lien si il le trouve
  2149.                   // suspect, et modifier alors adr et fil
  2150.                   // dans ce cas on aura une rΘfΘrence directe au lieu des traditionnels
  2151.                   // moved en cascade (impossible α reproduire α priori en local, lorsque des fichiers
  2152.                   // gif sont impliquΘs par exemple)
  2153.                   if ((p_type!=2) && (p_type!=-2)) {  // pas base href ou codebase
  2154.                     if (forbidden_url!=1) {
  2155.                       char last_adr[HTS_URLMAXSIZE*2];
  2156.                       last_adr[0]='\0';
  2157.                       //char last_fil[HTS_URLMAXSIZE*2]="";
  2158.                       strcpybuff(last_adr,adr);    // ancienne adresse
  2159.                       //strcpybuff(last_fil,fil);    // ancien chemin
  2160.                       r_sv=url_savename(adr,fil,save,former_adr,former_fil,liens[ptr]->adr,liens[ptr]->fil,opt,liens,lien_tot,back,back_max,cache,hash,ptr,numero_passe);
  2161.                       if (strcmp(jump_identification(last_adr),jump_identification(adr)) != 0) {  // a changΘ
  2162.                         
  2163.                         // 2e test si moved
  2164.                         
  2165.                         // Tester si un lien doit Ωtre acceptΘ ou refusΘ (wizard)
  2166.                         // forbidden_url=1 : lien refusΘ
  2167.                         // forbidden_url=0 : lien acceptΘ
  2168.                         if ((ptr>0) && (p_type!=2) && (p_type!=-2)) {    // tester autorisations?
  2169.                           if (!p_nocatch) {
  2170.                             if (adr[0]!='\0') {          
  2171.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  2172.                                 fspc(opt->log,"debug"); fprintf(opt->log,"wizard moved link retest at %s%s.."LF,adr,fil);
  2173.                                 test_flush;
  2174.                               }
  2175.                               forbidden_url=hts_acceptlink(opt,ptr,lien_tot,liens,
  2176.                                 adr,fil,
  2177.                                 &set_prio_to,
  2178.                                 &just_test_it);
  2179.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  2180.                                 fspc(opt->log,"debug"); fprintf(opt->log,"result for wizard moved link retest: %d"LF,forbidden_url);
  2181.                                 test_flush;
  2182.                               }
  2183.                             }
  2184.                           }
  2185.                         }
  2186.                         
  2187.                         //import_done=1;    // c'est un import!
  2188.                         meme_adresse=0;   // on a changΘ
  2189.                       }
  2190.                     } else {
  2191.                       strcpybuff(save,"");  // dummy
  2192.                     }
  2193.                   }
  2194.                   if (r_sv!=-1) {  // pas d'erreur, on continue
  2195.                     /* log */
  2196.                     if ((opt->debug>1) && (opt->log!=NULL)) {
  2197.                       fspc(opt->log,"debug");
  2198.                       if (forbidden_url!=1) {    // le lien va Ωtre chargΘ
  2199.                         if ((p_type==2) || (p_type==-2)) {  // base href ou codebase, pas un lien
  2200.                           fprintf(opt->log,"Code/Codebase: %s%s"LF,adr,fil);
  2201.                         } else if ((opt->getmode & 4)==0) {
  2202.                           fprintf(opt->log,"Record: %s%s -> %s"LF,adr,fil,save);
  2203.                         } else {
  2204.                           if (!ishtml(fil))
  2205.                             fprintf(opt->log,"Record after: %s%s -> %s"LF,adr,fil,save);
  2206.                           else
  2207.                             fprintf(opt->log,"Record: %s%s -> %s"LF,adr,fil,save);
  2208.                         } 
  2209.                       } else
  2210.                         fprintf(opt->log,"External: %s%s"LF,adr,fil);
  2211.                       test_flush;
  2212.                     }
  2213.                     /* FIN log */
  2214.                     
  2215.                     // Θcrire lien
  2216.                     if ((p_type==2) || (p_type==-2)) {  // base href ou codebase, sauter
  2217.                       lastsaved=eadr-1+1;  // sauter "
  2218.                     }
  2219.                     /* */
  2220.                     else if (opt->urlmode==0) {    // URL absolue dans tous les cas
  2221.                       if ((opt->getmode & 1) && (ptr>0)) {    // ecrire les html
  2222.                         if (!link_has_authority(adr)) {
  2223.                           HT_ADD("http://");
  2224.                         } else {
  2225.                           char* aut = strstr(adr, "//");
  2226.                           if (aut) {
  2227.                             char tmp[256];
  2228.                             tmp[0]='\0';
  2229.                             strncatbuff(tmp, adr, (int) (aut - adr));   // scheme
  2230.                             HT_ADD(tmp);          // Protocol
  2231.                             HT_ADD("//");
  2232.                           }
  2233.                         }
  2234.                         
  2235.                         if (!opt->passprivacy) {
  2236.                           HT_ADD(jump_protocol(adr));           // Password
  2237.                         } else {
  2238.                           HT_ADD(jump_identification(adr));     // No Password
  2239.                         }
  2240.                         if (*fil!='/')
  2241.                           HT_ADD("/");
  2242.                         HT_ADD(fil);
  2243.                       }
  2244.                       lastsaved=eadr-1;    // dernier Θcrit+1 (enfin euh apres on fait un ++ alors hein)
  2245.                       /* */
  2246.                     } else if (opt->urlmode >= 4) {    // ne rien faire dans tous les cas!
  2247.                       /* */
  2248.                       /* leave the link 'as is' */
  2249.                       /* Sinon, dΘpend de interne/externe */
  2250.                     } else if (forbidden_url==1) {    // le lien ne sera pas chargΘ, rΘfΘrence externe!
  2251.                       if ((opt->getmode & 1) && (ptr>0)) {
  2252.                         if (p_type!=-1) {     // pas que le nom de fichier (pas classe java)
  2253.                           if (!opt->external) {
  2254.                             if (!link_has_authority(adr)) {
  2255.                               HT_ADD("http://");
  2256.                               if (!opt->passprivacy) {
  2257.                                 HT_ADD(adr);     // Password
  2258.                               } else {
  2259.                                 HT_ADD(jump_identification(adr));     // No Password
  2260.                               }
  2261.                               if (*fil!='/')
  2262.                                 HT_ADD("/");
  2263.                               HT_ADD(fil);
  2264.                             } else {
  2265.                               char* aut = strstr(adr, "//");
  2266.                               if (aut) {
  2267.                                 char tmp[256];
  2268.                                 tmp[0]='\0';
  2269.                                 strncatbuff(tmp, adr, (int) (aut - adr));   // scheme
  2270.                                 HT_ADD(tmp);          // Protocol
  2271.                                 HT_ADD("//");
  2272.                                 if (!opt->passprivacy) {
  2273.                                   HT_ADD(jump_protocol(adr));          // Password
  2274.                                 } else {
  2275.                                   HT_ADD(jump_identification(adr));     // No Password
  2276.                                 }
  2277.                                 if (*fil!='/')
  2278.                                   HT_ADD("/");
  2279.                                 HT_ADD(fil);
  2280.                               }
  2281.                             }
  2282.                             //
  2283.                           } else {    // fichier/page externe, mais on veut gΘnΘrer une erreur
  2284.                             //
  2285.                             int patch_it=0;
  2286.                             int add_url=0;
  2287.                             char* cat_name=NULL;
  2288.                             char* cat_data=NULL;
  2289.                             int cat_nb=0;
  2290.                             int cat_data_len=0;
  2291.                             
  2292.                             // ajouter lien external
  2293.                             switch ( (link_has_authority(adr)) ? 1 : ( (fil[strlen(fil)-1]=='/')?1:(ishtml(fil))  ) ) {
  2294.                             case 1: case -2:       // html ou rΘpertoire
  2295.                               if (opt->getmode & 1) {  // sauver html
  2296.                                 patch_it=1;   // redirect
  2297.                                 add_url=1;    // avec link?
  2298.                                 cat_name="external.html";
  2299.                                 cat_nb=0;
  2300.                                 cat_data=HTS_DATA_UNKNOWN_HTML;
  2301.                                 cat_data_len=HTS_DATA_UNKNOWN_HTML_LEN;
  2302.                               }
  2303.                               break;
  2304.                             default:    // inconnu
  2305.                               // asp, cgi..
  2306.                               if ( (strfield2(fil+max(0,(int)strlen(fil)-4),".gif")) 
  2307.                                 || (strfield2(fil+max(0,(int)strlen(fil)-4),".jpg")) 
  2308.                                 || (strfield2(fil+max(0,(int)strlen(fil)-4),".xbm")) 
  2309.                                 /*|| (ishtml(fil)!=0)*/ ) {
  2310.                                 patch_it=1;   // redirect
  2311.                                 add_url=1;    // avec link aussi
  2312.                                 cat_name="external.gif";
  2313.                                 cat_nb=1;
  2314.                                 cat_data=HTS_DATA_UNKNOWN_GIF;
  2315.                                 cat_data_len=HTS_DATA_UNKNOWN_GIF_LEN;
  2316.                               } else /* if (is_dyntype(get_ext(fil))) */ {
  2317.                                 patch_it=1;   // redirect
  2318.                                 add_url=1;    // avec link?
  2319.                                 cat_name="external.html";
  2320.                                 cat_nb=0;
  2321.                                 cat_data=HTS_DATA_UNKNOWN_HTML;
  2322.                                 cat_data_len=HTS_DATA_UNKNOWN_HTML_LEN;
  2323.                               }
  2324.                               break;
  2325.                             }// html,gif
  2326.                             
  2327.                             if (patch_it) {
  2328.                               char save[HTS_URLMAXSIZE*2];
  2329.                               char tempo[HTS_URLMAXSIZE*2];
  2330.                               strcpybuff(save,opt->path_html);
  2331.                               strcatbuff(save,cat_name);
  2332.                               if (lienrelatif(tempo,save, relativesavename)==0) {
  2333.                                 if (!no_esc_utf)
  2334.                                   escape_uri(tempo);     // escape with %xx
  2335.                                 else
  2336.                                   escape_uri_utf(tempo);     // escape with %xx
  2337.                                 HT_ADD(tempo);    // page externe
  2338.                                 if (add_url) {
  2339.                                   HT_ADD("?link=");    // page externe
  2340.                                   
  2341.                                   // same as above
  2342.                                   if (!link_has_authority(adr)) {
  2343.                                     HT_ADD("http://");
  2344.                                     if (!opt->passprivacy) {
  2345.                                       HT_ADD(adr);     // Password
  2346.                                     } else {
  2347.                                       HT_ADD(jump_identification(adr));     // No Password
  2348.                                     }
  2349.                                     if (*fil!='/')
  2350.                                       HT_ADD("/");
  2351.                                     HT_ADD(fil);
  2352.                                   } else {
  2353.                                     char* aut = strstr(adr, "//");
  2354.                                     if (aut) {
  2355.                                       char tmp[256];
  2356.                                       tmp[0]='\0';
  2357.                                       strncatbuff(tmp, adr, (int) (aut - adr) + 2);   // scheme
  2358.                                       HT_ADD(tmp);
  2359.                                       if (!opt->passprivacy) {
  2360.                                         HT_ADD(jump_protocol(adr));          // Password
  2361.                                       } else {
  2362.                                         HT_ADD(jump_identification(adr));     // No Password
  2363.                                       }
  2364.                                       if (*fil!='/')
  2365.                                         HT_ADD("/");
  2366.                                       HT_ADD(fil);
  2367.                                     }
  2368.                                   }
  2369.                                   //
  2370.                                   
  2371.                                 }
  2372.                               }
  2373.                               
  2374.                               // Θcrire fichier?
  2375.                               if (verif_external(cat_nb,1)) {
  2376.                                 //if (!fexist(fconcat(opt->path_html,cat_name))) {
  2377.                                 FILE* fp = filecreate(fconcat(opt->path_html,cat_name));
  2378.                                 if (fp) {
  2379.                                   if (cat_data_len==0) {   // texte
  2380.                                     verif_backblue(opt,opt->path_html);
  2381.                                     fprintf(fp,"%s%s","<!-- Created by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->"LF,cat_data);
  2382.                                   } else {                    // data
  2383.                                     fwrite(cat_data,cat_data_len,1,fp);
  2384.                                   }
  2385.                                   fclose(fp);
  2386.                                   usercommand(opt,0,NULL,fconcat(opt->path_html,cat_name),"","");
  2387.                                 }
  2388.                               }
  2389.                             }  else {    // Θcrire normalement le nom de fichier
  2390.                               HT_ADD("http://");
  2391.                               if (!opt->passprivacy) {
  2392.                                 HT_ADD(adr);       // Password
  2393.                               } else {
  2394.                                 HT_ADD(jump_identification(adr));       // No Password
  2395.                               }
  2396.                               if (*fil!='/')
  2397.                                 HT_ADD("/");
  2398.                               HT_ADD(fil);
  2399.                             }// patcher?
  2400.                             }  // external
  2401.                           } else {  // que le nom de fichier (classe java)
  2402.                             // en gros recopie de plus bas: copier codebase et base
  2403.                             if (p_flush) {
  2404.                               char tempo[HTS_URLMAXSIZE*2];    // <-- ajoutΘ
  2405.                               char tempo_pat[HTS_URLMAXSIZE*2];
  2406.                               
  2407.                               // Calculer chemin
  2408.                               tempo_pat[0]='\0';
  2409.                               strcpybuff(tempo,fil);  // <-- ajoutΘ
  2410.                               {
  2411.                                 char* a=strrchr(tempo,'/');
  2412.                                 
  2413.                                 // Example: we converted code="x.y.z.foo.class" into "x/y/z/foo.class"
  2414.                                 // we have to do the contrary now
  2415.                                 if (add_class_dots_to_patch>0) {
  2416.                                   while( (add_class_dots_to_patch>0) && (a) ) {
  2417.                                     *a='.';     // convert "false" java / into .
  2418.                                     add_class_dots_to_patch--;
  2419.                                     a=strrchr(tempo,'/');
  2420.                                   }
  2421.                                   // if add_class_dots_to_patch, this is because there is a problem!!
  2422.                                   if (add_class_dots_to_patch) {
  2423.                                     if (opt->errlog) {
  2424.                                       fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Error: can not rewind java path %s, check html code"LF,tempo);
  2425.                                       test_flush;
  2426.                                     }
  2427.                                   }
  2428.                                 }
  2429.                                 
  2430.                                 // Cut path/filename
  2431.                                 if (a) {
  2432.                                   char tempo2[HTS_URLMAXSIZE*2];
  2433.                                   strcpybuff(tempo2,a+1);         // FICHIER
  2434.                                   strncatbuff(tempo_pat,tempo,(int) (a - tempo)+1);  // chemin
  2435.                                   strcpybuff(tempo,tempo2);                     // fichier
  2436.                                 }
  2437.                               }
  2438.                               
  2439.                               // Θrire codebase="chemin"
  2440.                               if ((opt->getmode & 1) && (ptr>0)) {
  2441.                                 char tempo4[HTS_URLMAXSIZE*2];
  2442.                                 tempo4[0]='\0';
  2443.                                 
  2444.                                 if (strnotempty(tempo_pat)) {
  2445.                                   HT_ADD("codebase=\"http://");
  2446.                                   if (!opt->passprivacy) {
  2447.                                     HT_ADD(adr);  // Password
  2448.                                   } else {
  2449.                                     HT_ADD(jump_identification(adr));  // No Password
  2450.                                   }
  2451.                                   if (*tempo_pat!='/') HT_ADD("/");
  2452.                                   HT_ADD(tempo_pat);
  2453.                                   HT_ADD("\" ");
  2454.                                 }
  2455.                                 
  2456.                                 strncatbuff(tempo4,lastsaved,(int) (p_flush - lastsaved));
  2457.                                 HT_ADD(tempo4);    // refresh code="
  2458.                                 HT_ADD(tempo);
  2459.                               }
  2460.                             }
  2461.                           }
  2462.                         }
  2463.                         lastsaved=eadr-1;
  2464.                       }
  2465.                       /*
  2466.                       else if (opt->urlmode==1) {    // ABSOLU, c'est le cas le moins courant
  2467.                       //  NE FONCTIONNE PAS!!  (et est inutile)
  2468.                       if ((opt->getmode & 1) && (ptr>0)) {    // ecrire les html
  2469.                       // Θcrire le lien modifiΘ, absolu
  2470.                       HT_ADD("file:");
  2471.                       if (*save=='/')
  2472.                       HT_ADD(save+1)
  2473.                       else
  2474.                       HT_ADD(save)
  2475.                       }
  2476.                       lastsaved=eadr-1;    // dernier Θcrit+1 (enfin euh apres on fait un ++ alors hein)
  2477.                       }
  2478.                       */
  2479.                     else if (opt->mimehtml) {
  2480.                       char buff[HTS_URLMAXSIZE*3];
  2481.                       HT_ADD("cid:");
  2482.                       strcpybuff(buff, adr);
  2483.                       strcatbuff(buff, fil);
  2484.                       escape_in_url(buff);
  2485.                       { char* a = buff; while((a = strchr(a, '%'))) { *a = 'X'; a++; } }
  2486.                       HT_ADD(buff);
  2487.                       lastsaved=eadr-1;    // dernier Θcrit+1 (enfin euh apres on fait un ++ alors hein)
  2488.                     }
  2489.                     else if (opt->urlmode==3) {    // URI absolue /
  2490.                       if ((opt->getmode & 1) && (ptr>0)) {    // ecrire les html
  2491.                         HT_ADD(fil);
  2492.                       }
  2493.                       lastsaved=eadr-1;    // dernier Θcrit+1 (enfin euh apres on fait un ++ alors hein)
  2494.                     }
  2495.                     else if (opt->urlmode==2) {  // RELATIF
  2496.                         char tempo[HTS_URLMAXSIZE*2];
  2497.                         tempo[0]='\0';
  2498.                         // calculer le lien relatif
  2499.                         
  2500.                         if (lienrelatif(tempo,save,relativesavename)==0) {
  2501.                           if (!no_esc_utf)
  2502.                             escape_uri(tempo);     // escape with %xx
  2503.                           else
  2504.                             escape_uri_utf(tempo);     // escape with %xx
  2505.                           if ((opt->debug>1) && (opt->log!=NULL)) {
  2506.                             fspc(opt->log,"debug"); fprintf(opt->log,"relative link at %s build with %s and %s: %s"LF,adr,save,relativesavename,tempo);
  2507.                             test_flush;
  2508.                           }
  2509.                           
  2510.                           // lien applet (code) - il faut placer un codebase avant
  2511.                           if (p_type==-1) {  // que le nom de fichier
  2512.                             
  2513.                             if (p_flush) {
  2514.                               char tempo_pat[HTS_URLMAXSIZE*2];
  2515.                               tempo_pat[0]='\0';
  2516.                               {
  2517.                                 char* a=strrchr(tempo,'/');
  2518.                                 
  2519.                                 // Example: we converted code="x.y.z.foo.class" into "x/y/z/foo.class"
  2520.                                 // we have to do the contrary now
  2521.                                 if (add_class_dots_to_patch>0) {
  2522.                                   while( (add_class_dots_to_patch>0) && (a) ) {
  2523.                                     *a='.';     // convert "false" java / into .
  2524.                                     add_class_dots_to_patch--;
  2525.                                     a=strrchr(tempo,'/');
  2526.                                   }
  2527.                                   // if add_class_dots_to_patch, this is because there is a problem!!
  2528.                                   if (add_class_dots_to_patch) {
  2529.                                     if (opt->errlog) {
  2530.                                       fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Error: can not rewind java path %s, check html code"LF,tempo);
  2531.                                       test_flush;
  2532.                                     }
  2533.                                   }
  2534.                                 }
  2535.                                 
  2536.                                 if (a) {
  2537.                                   char tempo2[HTS_URLMAXSIZE*2];
  2538.                                   strcpybuff(tempo2,a+1);
  2539.                                   strncatbuff(tempo_pat,tempo,(int) (a - tempo)+1);  // chemin
  2540.                                   strcpybuff(tempo,tempo2);                     // fichier
  2541.                                 }
  2542.                               }
  2543.                               
  2544.                               // Θrire codebase="chemin"
  2545.                               if ((opt->getmode & 1) && (ptr>0)) {
  2546.                                 char tempo4[HTS_URLMAXSIZE*2];
  2547.                                 tempo4[0]='\0';
  2548.                                 
  2549.                                 if (strnotempty(tempo_pat)) {
  2550.                                   HT_ADD("codebase=\"");
  2551.                                   HT_ADD(tempo_pat);
  2552.                                   HT_ADD("\" ");
  2553.                                 }
  2554.                                 
  2555.                                 strncatbuff(tempo4,lastsaved,(int) (p_flush - lastsaved));
  2556.                                 HT_ADD(tempo4);    // refresh code="
  2557.                               }
  2558.                             }
  2559.                             //lastsaved=adr;    // dernier Θcrit+1
  2560.                           }                              
  2561.                           
  2562.                           if ((opt->getmode & 1) && (ptr>0)) {
  2563.                             // Θcrire le lien modifiΘ, relatif
  2564.                             HT_ADD(tempo);
  2565.                             
  2566.                             // Add query-string, for informational purpose only
  2567.                             // Useless, because all parameters-pages are saved into different targets
  2568.                             if (opt->includequery) {
  2569.                               char* a=strchr(lien,'?');
  2570.                               if (a) {
  2571.                                 HT_ADD(a);
  2572.                               }
  2573.                             }
  2574.                           }
  2575.                           lastsaved=eadr-1;    // dernier Θcrit+1 (enfin euh apres on fait un ++ alors hein)
  2576.                         } else {
  2577.                           if (opt->errlog) {
  2578.                             fprintf(opt->errlog,"Error building relative link %s and %s"LF,save,relativesavename);
  2579.                             test_flush;
  2580.                           }
  2581.                         }
  2582.                       }  // sinon le lien sera Θcrit normalement
  2583.                       
  2584.                       
  2585. #if 0
  2586.                       if (fexist(save)) {    // le fichier existe..
  2587.                         adr[0]='\0';
  2588.                         //if ((opt->debug>0) && (opt->log!=NULL)) {
  2589.                         if (opt->errlog) {
  2590.                           fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Link has already been written on disk, cancelled: %s"LF,save);
  2591.                           test_flush;
  2592.                         }
  2593.                       }
  2594. #endif                            
  2595.                       
  2596.                       /* Security check */
  2597.                       if (strlen(save) >= HTS_URLMAXSIZE) {
  2598.                         adr[0]='\0';
  2599.                         if (opt->errlog) {
  2600.                           fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Link is too long: %s"LF,save);
  2601.                           test_flush;
  2602.                         }
  2603.                       }
  2604.                       
  2605.                       if ((adr[0]!='\0') && (p_type!=2) && (p_type!=-2) && (forbidden_url!=1) ) {  // si le fichier n'existe pas, ajouter α la liste                            
  2606.                         // n'y a-t-il pas trop de liens?
  2607.                         if (lien_tot+1 >= lien_max-4) {    // trop de liens!
  2608.                           printf("PANIC! : Too many URLs : >%d [%d]\n",lien_tot,__LINE__);
  2609.                           if (opt->errlog) {
  2610.                             fprintf(opt->errlog,LF"Too many URLs, giving up..(>%d)"LF,lien_max);
  2611.                             fprintf(opt->errlog,"To avoid that: use #L option for more links (example: -#L1000000)"LF);
  2612.                             test_flush;
  2613.                           }
  2614.                           if ((opt->getmode & 1) && (ptr>0)) { if (fp) { fclose(fp); fp=NULL; } }
  2615.                           XH_uninit;   // dΘsallocation mΘmoire & buffers
  2616.                           return -1;
  2617.                           
  2618.                         } else {    // noter le lien sur la listes des liens α charger
  2619.                           int pass_fix,dejafait=0;
  2620.                           
  2621.                           // Calculer la prioritΘ de ce lien
  2622.                           if ((opt->getmode & 4)==0) {    // traiter html aprΦs
  2623.                             pass_fix=0;
  2624.                           } else {    // vΘrifier que ce n'est pas un !html
  2625.                             if (!ishtml(fil))
  2626.                               pass_fix=1;        // prioritΘ infΘrieure (traiter aprΦs)
  2627.                             else
  2628.                               pass_fix=max(0,numero_passe);    // prioritΘ normale
  2629.                           }
  2630.                           
  2631.                           /* If the file seems to be an html file, get depth-1 */
  2632.                           /*
  2633.                           if (strnotempty(save)) {
  2634.                           if (ishtml(save) == 1) {
  2635.                           // descore_prio = 2;
  2636.                           } else {
  2637.                           // descore_prio = 1;
  2638.                           }
  2639.                           }
  2640.                           */
  2641.                           
  2642.                           // vΘrifier que le lien n'a pas dΘja ΘtΘ notΘ
  2643.                           // si c'est le cas, alors il faut s'assurer que la prioritΘ associΘe
  2644.                           // au fichier est la plus grande des deux prioritΘs
  2645.                           //
  2646.                           // On part de la fin et on essaye de se presser (Θconomise temps machine)
  2647. #if HTS_HASH
  2648.                           {
  2649.                             int i=hash_read(hash,save,"",0,opt->urlhack);      // lecture type 0 (sav)
  2650.                             if (i>=0) {
  2651.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  2652.                                 if (
  2653.                                   strcmp(adr, liens[i]->adr) != 0 
  2654.                                   || strcmp(fil, liens[i]->fil) != 0
  2655.                                   ) {
  2656.                                   fspc(opt->log,"debug"); fprintf(opt->log,"merging similar links %s%s and %s%s"LF,adr,fil,liens[i]->adr,liens[i]->fil);
  2657.                                   test_flush;
  2658.                                 }
  2659.                               }
  2660.                               liens[i]->depth=maximum(liens[i]->depth,liens[ptr]->depth - 1);
  2661.                               dejafait=1;
  2662.                             }
  2663.                           }
  2664. #else
  2665.                           {
  2666.                             int l;
  2667.                             int i;
  2668.                             l=strlen(save);  // opti
  2669.                             for(i=lien_tot-1;(i>=0) && (dejafait==0);i--) {
  2670.                               if (liens[i]->sav_len==l) {    // mΩme taille de chaεne
  2671.                                 if (strcmp(liens[i]->sav,save)==0) {    // existe dΘja
  2672.                                   liens[i]->depth=maximum(liens[i]->depth,liens[ptr]->depth - 1);
  2673.                                   dejafait=1;
  2674.                                 }
  2675.                               }
  2676.                             }
  2677.                           }
  2678. #endif
  2679.                           
  2680.                           // le lien n'a jamais ΘtΘ crΘΘ.
  2681.                           // cette fois ci, on le crΘe!
  2682.                           if (!dejafait) {                                
  2683.                             //
  2684.                             // >>>> CREER LE LIEN <<<<
  2685.                             //
  2686.                             // enregistrer lien α charger
  2687.                             //liens[lien_tot]->adr[0]=liens[lien_tot]->fil[0]=liens[lien_tot]->sav[0]='\0';
  2688.                             // mΩme adresse: l'objet pΦre est l'objet pΦre de l'actuel
  2689.                             
  2690.                             // DEBUT ROBOTS.TXT AJOUT
  2691.                             if (!just_test_it) {
  2692.                               if (
  2693.                                 (!strfield(adr,"ftp://"))         // non ftp
  2694.                                 && (!strfield(adr,"file://")) ) {    // non file
  2695.                                 if (opt->robots) {    // rΘcupΘrer robots
  2696.                                   if (ishtml(fil)!=0) {                       // pas la peine pour des fichiers isolΘs
  2697.                                     if (checkrobots(_ROBOTS,adr,"") != -1) {    // robots.txt ?
  2698.                                       checkrobots_set(_ROBOTS ,adr,"");          // ajouter entrΘe vide
  2699.                                       if (checkrobots(_ROBOTS,adr,"") == -1) {    // robots.txt ?
  2700.                                         // enregistrer robots.txt (MACRO)
  2701.                                         liens_record(adr,"/robots.txt","","","");
  2702.                                         if (liens[lien_tot]==NULL) {  // erreur, pas de place rΘservΘe
  2703.                                           printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  2704.                                           if (opt->errlog) { 
  2705.                                             fprintf(opt->errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  2706.                                             test_flush;
  2707.                                           }
  2708.                                           if ((opt->getmode & 1) && (ptr>0)) { if (fp) { fclose(fp); fp=NULL; } }
  2709.                                           XH_uninit;    // dΘsallocation mΘmoire & buffers
  2710.                                           return -1;
  2711.                                         }  
  2712.                                         liens[lien_tot]->testmode=0;          // pas mode test
  2713.                                         liens[lien_tot]->link_import=0;       // pas mode import     
  2714.                                         liens[lien_tot]->premier=lien_tot;
  2715.                                         liens[lien_tot]->precedent=ptr;
  2716.                                         liens[lien_tot]->depth=0;
  2717.                                         liens[lien_tot]->pass2=max(0,numero_passe);
  2718.                                         liens[lien_tot]->retry=0;
  2719.                                         lien_tot++;  // UN LIEN DE PLUS
  2720. #if DEBUG_ROBOTS
  2721.                                         printf("robots.txt: added file robots.txt for %s\n",adr);
  2722. #endif
  2723.                                         if ((opt->debug>1) && (opt->log!=NULL)) {
  2724.                                           fspc(opt->log,"debug"); fprintf(opt->log,"robots.txt added at %s"LF,adr);
  2725.                                           test_flush;
  2726.                                         }
  2727.                                       } else {
  2728.                                         if (opt->errlog) {   
  2729.                                           fprintf(opt->errlog,"Unexpected robots.txt error at %d"LF,__LINE__);
  2730.                                           test_flush;
  2731.                                         }
  2732.                                       }
  2733.                                     }
  2734.                                   }
  2735.                                 }
  2736.                               }
  2737.                             }
  2738.                             // FIN ROBOTS.TXT AJOUT
  2739.                             
  2740.                             // enregistrer (MACRO)
  2741.                             liens_record(adr,fil,save,former_adr,former_fil);
  2742.                             if (liens[lien_tot]==NULL) {  // erreur, pas de place rΘservΘe
  2743.                               printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  2744.                               if (opt->errlog) { 
  2745.                                 fprintf(opt->errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  2746.                                 test_flush;
  2747.                               }
  2748.                               if ((opt->getmode & 1) && (ptr>0)) { if (fp) { fclose(fp); fp=NULL; } }
  2749.                               XH_uninit;    // dΘsallocation mΘmoire & buffers
  2750.                               return -1;
  2751.                             }  
  2752.                             
  2753.                             // mode test?
  2754.                             if (!just_test_it)
  2755.                               liens[lien_tot]->testmode=0;          // pas mode test
  2756.                             else
  2757.                               liens[lien_tot]->testmode=1;          // mode test
  2758.                             if (!import_done)
  2759.                               liens[lien_tot]->link_import=0;       // pas mode import
  2760.                             else
  2761.                               liens[lien_tot]->link_import=1;       // mode import
  2762.                             // Θcrire autres paramΦtres de la structure-lien
  2763.                             if ((meme_adresse) && (!import_done) && (liens[ptr]->premier != 0))
  2764.                               liens[lien_tot]->premier=liens[ptr]->premier;
  2765.                             else    // sinon l'objet pΦre est le prΘcΘdent lui mΩme
  2766.                               liens[lien_tot]->premier=lien_tot;
  2767.                             // liens[lien_tot]->premier=ptr;
  2768.                             
  2769.                             liens[lien_tot]->precedent=ptr;
  2770.                             // noter la prioritΘ
  2771.                             if (!set_prio_to)
  2772.                               liens[lien_tot]->depth=liens[ptr]->depth - 1;
  2773.                             else
  2774.                               liens[lien_tot]->depth=max(0,min(liens[ptr]->depth-1,set_prio_to-1));         // PRIORITE NULLE (catch page)
  2775.                             // noter pass
  2776.                             liens[lien_tot]->pass2=pass_fix;
  2777.                             liens[lien_tot]->retry=opt->retry;
  2778.                             
  2779.                             //strcpybuff(liens[lien_tot]->adr,adr);
  2780.                             //strcpybuff(liens[lien_tot]->fil,fil);
  2781.                             //strcpybuff(liens[lien_tot]->sav,save); 
  2782.                             if ((opt->debug>1) && (opt->log!=NULL)) {
  2783.                               if (!just_test_it) {
  2784.                                 fspc(opt->log,"debug"); fprintf(opt->log,"OK, NOTE: %s%s -> %s"LF,liens[lien_tot]->adr,liens[lien_tot]->fil,liens[lien_tot]->sav);
  2785.                               } else {
  2786.                                 fspc(opt->log,"debug"); fprintf(opt->log,"OK, TEST: %s%s"LF,liens[lien_tot]->adr,liens[lien_tot]->fil);
  2787.                               }
  2788.                               test_flush;
  2789.                             }
  2790.                             
  2791.                             lien_tot++;  // UN LIEN DE PLUS
  2792.                           } else { // if !dejafait
  2793.                             if ((opt->debug>1) && (opt->log!=NULL)) {
  2794.                               fspc(opt->log,"debug"); fprintf(opt->log,"link has already been recorded, cancelled: %s"LF,save);
  2795.                               test_flush;
  2796.                             }
  2797.                             
  2798.                           }
  2799.                           
  2800.                           
  2801.                         }   // si pas trop de liens
  2802.                       }   // si adr[0]!='\0'
  2803.                       
  2804.                       
  2805.                     }  // if adr[0]!='\0' 
  2806.                     
  2807.                   }  // if adr[0]!='\0'
  2808.                   
  2809.                 }    // if strlen(lien)>0
  2810.                 
  2811.               }   // if ok==0      
  2812.               
  2813.               adr=eadr-1;  // ** sauter
  2814.  
  2815.               /* We skipped bytes and skip the " : reset state */
  2816.               if (inscript) {
  2817.                 inscript_state_pos = INSCRIPT_START;
  2818.               }
  2819.  
  2820.             }  // if (p) 
  2821.             
  2822.           }  // si '<' ou '>'
  2823.           
  2824.           // plus loin
  2825.           adr++;
  2826.           
  2827.           
  2828.           /* Otimization: if we are scanning in HTML data (not in tag or script), 
  2829.           then jump to the next starting tag */
  2830.           if (ptr>0) {
  2831.             if ( (!intag)         /* Not in tag */
  2832.               && (!inscript)      /* Not in (java)script */
  2833.               && (!incomment)     /* Not in comment (<!--) */
  2834.               && (!inscript_tag)  /* Not in tag with script inside */
  2835.               ) 
  2836.             {
  2837.               /* Not at the end */
  2838.               if (( ((int) (adr - r->adr)) ) < r->size) {
  2839.                 /* Not on a starting tag yet */
  2840.                 if (*adr != '<') {
  2841.                   /* strchr does not well behave with null chrs.. */
  2842.                   /* char* adr_next = strchr(adr,'<'); */
  2843.                   char* adr_next = adr;
  2844.                   while(*adr_next != '<' && (adr_next - r->adr) < r->size ) {
  2845.                     adr_next++;
  2846.                   }
  2847.                   /* Jump to near end (index hack) */
  2848.                   if (!adr_next || *adr_next != '<') {
  2849.                     if (
  2850.                       ( (int)(adr - r->adr) < (r->size - 4)) 
  2851.                       &&
  2852.                       (r->size > 4)
  2853.                       ) {
  2854.                       adr = r->adr + r->size - 2;
  2855.                     }
  2856.                   } else {
  2857.                     adr = adr_next;
  2858.                   }
  2859.                 }
  2860.               }
  2861.             }
  2862.           }
  2863.           
  2864.           // ----------
  2865.           // Θcrire peu α peu
  2866.           if ((opt->getmode & 1) && (ptr>0)) HT_ADD_ADR;
  2867.           lastsaved=adr;    // dernier Θcrit+1
  2868.           // ----------
  2869.  
  2870.           // Checks
  2871.           if (back_add_stats != opt->state.back_add_stats) {
  2872.             back_add_stats = opt->state.back_add_stats;
  2873.  
  2874.             // Check max time
  2875.             if (!back_checkmirror(opt)) {
  2876.               adr = r->adr + r->size;
  2877.             }
  2878.           }
  2879.  
  2880.           // pour les stats du shell si parsing trop long
  2881. #if HTS_ANALYSTE
  2882.           if (r->size)
  2883.             _hts_in_html_done=(100 * ((int) (adr - r->adr)) ) / (int)(r->size);
  2884.           if (_hts_in_html_poll) {
  2885.             _hts_in_html_poll=0;
  2886.             // temps α attendre, et remplir autant que l'on peut le cache (backing)
  2887.             back_wait(back,back_max,opt,cache,HTS_STAT.stat_timestart);        
  2888.             back_fillmax(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot);
  2889.             
  2890.             // Transfer rate
  2891.             engine_stats();
  2892.             
  2893.             // Refresh various stats
  2894.             HTS_STAT.stat_nsocket=back_nsoc(back,back_max);
  2895.             HTS_STAT.stat_errors=fspc(NULL,"error");
  2896.             HTS_STAT.stat_warnings=fspc(NULL,"warning");
  2897.             HTS_STAT.stat_infos=fspc(NULL,"info");
  2898.             HTS_STAT.nbk=backlinks_done(liens,lien_tot,ptr);
  2899.             HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,back,back_max);
  2900.             
  2901.             if (!hts_htmlcheck_loop(back,back_max,0,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) {
  2902.               if (opt->errlog) {
  2903.                 fspc(opt->errlog,"info"); fprintf(opt->errlog,"Exit requested by shell or user"LF);
  2904.                 test_flush;
  2905.               } 
  2906.               *stre->exit_xh_=1;  // exit requested
  2907.               XH_uninit;
  2908.               return -1;
  2909.               //adr = r->adr + r->size;  // exit
  2910.             } else if (_hts_cancel==1) {
  2911.               // adr = r->adr + r->size;  // exit
  2912.               nofollow=1;               // moins violent
  2913.               _hts_cancel=0;
  2914.             }
  2915.           }
  2916.           
  2917.           // refresh the backing system each 2 seconds
  2918.           if (engine_stats()) {
  2919.             back_wait(back,back_max,opt,cache,HTS_STAT.stat_timestart);        
  2920.             back_fillmax(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot);
  2921.           }
  2922. #endif
  2923.         } while(( ((int) (adr - r->adr)) ) < r->size);
  2924. #if HTS_ANALYSTE
  2925.         _hts_in_html_parsing=0;  // flag
  2926.         _hts_cancel=0;           // pas de cancel
  2927. #endif
  2928.         if ((opt->getmode & 1) && (ptr>0)) {
  2929.           HT_ADD_END;    // achever
  2930.         }
  2931.         //
  2932.         //
  2933.         //
  2934.       }  // if !error
  2935.       
  2936.       
  2937.       if (opt->getmode & 1) { if (fp) { fclose(fp); fp=NULL; } }
  2938.       // sauver fichier
  2939.       //structcheck(savename);
  2940.       //filesave(opt,r->adr,r->size,savename);
  2941.       
  2942. #if HTS_ANALYSTE
  2943.     }  // analyse OK
  2944. #endif
  2945.  
  2946.     /* Apply changes */
  2947.     ENGINE_SAVE_CONTEXT();
  2948.     
  2949.     return 0;
  2950. }
  2951.  
  2952.  
  2953.  
  2954.  
  2955. /*
  2956.   Check 301, 302, .. statuscodes (moved)
  2957. */
  2958. int hts_mirror_check_moved(htsmoduleStruct* str, htsmoduleStructExtended* stre) {
  2959.   /* Load engine variables */
  2960.   ENGINE_LOAD_CONTEXT();  
  2961.   
  2962.   // DEBUT rattrapage des 301,302,307..
  2963.   // ------------------------------------------------------------
  2964.   if (!error) {
  2965.     ////////{
  2966.     // on a chargΘ un fichier en plus
  2967.     // if (!error) stat_loaded+=r.size;
  2968.     
  2969.     // ------------------------------------------------------------
  2970.     // Rattrapage des 301,302,307 (moved) et 412,416 - les 304 le sont dans le backing 
  2971.     // ------------------------------------------------------------
  2972.     if ( (r->statuscode==301) 
  2973.       || (r->statuscode==302)
  2974.       || (r->statuscode==303)
  2975.       || (r->statuscode==307)
  2976.       ) {          
  2977.       //if (r->adr!=NULL) {   // adr==null si fichier direct. [catch: davename normalement si cgi]
  2978.       //int i=0;
  2979.       char *rn=NULL;
  2980.       // char* p;
  2981.       
  2982.       if ( (opt->debug>0) && (opt->errlog!=NULL) ) {
  2983.         //if (opt->errlog) {
  2984.         fspc(opt->errlog,"warning"); fprintf(opt->errlog,"%s for %s%s"LF,r->msg,urladr,urlfil);
  2985.         test_flush;
  2986.       }
  2987.       
  2988.       
  2989.       {
  2990.         char mov_url[HTS_URLMAXSIZE*2],mov_adr[HTS_URLMAXSIZE*2],mov_fil[HTS_URLMAXSIZE*2];
  2991.         int get_it=0;         // ne pas prendre le fichier α la mΩme adresse par dΘfaut
  2992.         int reponse=0;
  2993.         mov_url[0]='\0'; mov_adr[0]='\0'; mov_fil[0]='\0';
  2994.         //
  2995.         
  2996.         strcpybuff(mov_url,r->location);
  2997.         
  2998.         // url qque -> adresse+fichier
  2999.         if ((reponse=ident_url_relatif(mov_url,urladr,urlfil,mov_adr,mov_fil))>=0) {                        
  3000.           int set_prio_to=0;    // pas de priotitΘ fixΘd par wizard
  3001.           
  3002.           //if (ident_url_absolute(mov_url,mov_adr,mov_fil)!=-1) {    // ok URL reconnue
  3003.           // c'est (en gros) la mΩme URL..
  3004.           // si c'est un problΦme de casse dans le host c'est que le serveur est buggΘ
  3005.           // ("RFC says.." : host name IS case insensitive)
  3006.           if ((strfield2(mov_adr,urladr)!=0) && (strfield2(mov_fil,urlfil)!=0)) {  // identique α casse prΦs
  3007.             // on tourne en rond
  3008.             if (strcmp(mov_fil,urlfil)==0) {
  3009.               error=1;
  3010.               get_it=-1;        // ne rien faire
  3011.               if (opt->errlog) {
  3012.                 fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Can not bear crazy server (%s) for %s%s"LF,r->msg,urladr,urlfil);
  3013.                 test_flush;
  3014.               }
  3015.             } else {    // mauvaise casse, effacer entrΘe dans la pile et rejouer une fois
  3016.               get_it=1;
  3017.             }
  3018.           } else {        // adresse diffΘrente
  3019.             if (ishtml(mov_url)==0) {   // pas mΩme adresse MAIS c'est un fichier non html (pas de page moved possible)
  3020.               // -> on prend α cette adresse, le lien sera enregistrΘ avec lien_record() (hash)
  3021.               if ((opt->debug>1) && (opt->log!=NULL)) {
  3022.                 fspc(opt->log,"debug"); fprintf(opt->log,"wizard link test for moved file at %s%s.."LF,mov_adr,mov_fil);
  3023.                 test_flush;
  3024.               }
  3025.               // acceptΘ?
  3026.               if (hts_acceptlink(opt,ptr,lien_tot,liens,
  3027.                 mov_adr,mov_fil,
  3028.                 &set_prio_to,
  3029.                 NULL) != 1) {                /* nouvelle adresse non refusΘe ? */
  3030.                 get_it=1;
  3031.                 if ((opt->debug>1) && (opt->log!=NULL)) {
  3032.                   fspc(opt->log,"debug"); fprintf(opt->log,"moved link accepted: %s%s"LF,mov_adr,mov_fil);
  3033.                   test_flush;
  3034.                 }
  3035.               }
  3036.             } /* sinon traitΘ normalement */
  3037.           }
  3038.           
  3039.           //if ((strfield2(mov_adr,urladr)!=0) && (strfield2(mov_fil,urlfil)!=0)) {  // identique α casse prΦs
  3040.           if (get_it==1) {
  3041.             // court-circuiter le reste du traitement
  3042.             // et reculer pour mieux sauter
  3043.             if (opt->errlog) {
  3044.               fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Warning moved treated for %s%s (real one is %s%s)"LF,urladr,urlfil,mov_adr,mov_fil);
  3045.               test_flush;
  3046.             }          
  3047.             // canceller lien actuel
  3048.             error=1;
  3049.             strcpybuff(liens[ptr]->adr,"!");  // caractΦre bidon (invalide hash)
  3050. #if HTS_HASH
  3051. #else
  3052.             liens[ptr]->sav_len=-1;       // taille invalide
  3053. #endif
  3054.             // noter NOUVEAU lien
  3055.             //xxc xxc
  3056.             //  set_prio_to=0+1;  // protection if the moved URL is an html page!!
  3057.             //xxc xxc
  3058.             {
  3059.               char mov_sav[HTS_URLMAXSIZE*2];
  3060.               // calculer lien et Θventuellement modifier addresse/fichier
  3061.               if (url_savename(mov_adr,mov_fil,mov_sav,NULL,NULL,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil,opt,liens,lien_tot,back,back_max,cache,hash,ptr,numero_passe)!=-1) { 
  3062.                 if (hash_read(hash,mov_sav,"",0,0)<0) {      // n'existe pas dΘja
  3063.                   // enregistrer lien (MACRO) avec SAV IDENTIQUE
  3064.                   liens_record(mov_adr,mov_fil,liens[ptr]->sav,"","");
  3065.                   //liens_record(mov_adr,mov_fil,mov_sav,"","");
  3066.                   if (liens[lien_tot]!=NULL) {    // OK, pas d'erreur
  3067.                     // mode test?
  3068.                     liens[lien_tot]->testmode=liens[ptr]->testmode;
  3069.                     liens[lien_tot]->link_import=0;       // mode normal
  3070.                     if (!set_prio_to)
  3071.                       liens[lien_tot]->depth=liens[ptr]->depth;
  3072.                     else
  3073.                       liens[lien_tot]->depth=max(0,min(set_prio_to-1,liens[ptr]->depth));       // PRIORITE NULLE (catch page)
  3074.                     liens[lien_tot]->pass2=max(liens[ptr]->pass2,numero_passe);
  3075.                     liens[lien_tot]->retry=liens[ptr]->retry;
  3076.                     liens[lien_tot]->premier=liens[ptr]->premier;
  3077.                     liens[lien_tot]->precedent=liens[ptr]->precedent;
  3078.                     lien_tot++;
  3079.                   } else {  // oups erreur, plus de mΘmoire!!
  3080.                     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  3081.                     if (opt->errlog) {
  3082.                       fprintf(opt->errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  3083.                       test_flush;
  3084.                     }
  3085.                     //if (opt->getmode & 1) { if (fp) { fclose(fp); fp=NULL; } }
  3086.                     XH_uninit;    // dΘsallocation mΘmoire & buffers
  3087.                     return 0;
  3088.                   }
  3089.                 } else {
  3090.                   if ( (opt->debug>0) && (opt->errlog!=NULL) ) {
  3091.                     fspc(opt->errlog,"warning"); fprintf(opt->errlog,"moving %s to an existing file %s"LF,liens[ptr]->fil,urlfil);
  3092.                     test_flush;
  3093.                   }
  3094.                 }
  3095.                 
  3096.               }
  3097.             }
  3098.             
  3099.             //printf("-> %s %s %s\n",liens[lien_tot-1]->adr,liens[lien_tot-1]->fil,liens[lien_tot-1]->sav);
  3100.             
  3101.             // note mΘtaphysique: il se peut qu'il y ait un index.html et un INDEX.HTML
  3102.             // sous DOS ca marche pas trΦs bien... mais comme je suis gΘnial url_savename()
  3103.             // est α mΩme de rΘgler ce problΦme
  3104.           }
  3105.             } // ident_url_xx
  3106.             
  3107.             if (get_it==0) {    // adresse vraiment diffΘrente et potentiellement en html (pas de possibilitΘ de bouger la page tel quel α cause des <img src..> et cie)
  3108.               rn=(char*) calloct(8192,1);
  3109.               if (rn!=NULL) {
  3110.                 if (opt->errlog) {
  3111.                   fspc(opt->errlog,"warning"); fprintf(opt->errlog,"File has moved from %s%s to %s"LF,urladr,urlfil,mov_url);
  3112.                   test_flush;
  3113.                 }
  3114.                 if (!opt->mimehtml) {
  3115.                   escape_uri(mov_url);
  3116.                 } else {
  3117.                   char buff[HTS_URLMAXSIZE*3];
  3118.                   strcpybuff(buff, mov_adr);
  3119.                   strcatbuff(buff, mov_fil);
  3120.                   escape_in_url(buff);
  3121.                   { char* a = buff; while((a = strchr(a, '%'))) { *a = 'X'; a++; } }
  3122.                   strcpybuff(mov_url, "cid:");
  3123.                   strcatbuff(mov_url, buff);
  3124.                 }
  3125.                 // On prΘpare une page qui sautera immΘdiatement sur la bonne URL
  3126.                 // Le scanner re-changera, ensuite, cette URL, pour la mirrorer!
  3127.                 strcpybuff(rn,"<HTML>"CRLF);
  3128.                 strcatbuff(rn,"<!-- Created by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->"CRLF);
  3129.                 strcatbuff(rn,"<HEAD>"CRLF"<TITLE>Page has moved</TITLE>"CRLF"</HEAD>"CRLF"<BODY>"CRLF);
  3130.                 strcatbuff(rn,"<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0; URL=");
  3131.                 strcatbuff(rn,mov_url);    // URL
  3132.                 strcatbuff(rn,"\">"CRLF);
  3133.                 strcatbuff(rn,"<A HREF=\"");
  3134.                 strcatbuff(rn,mov_url);
  3135.                 strcatbuff(rn,"\">");
  3136.                 strcatbuff(rn,"<B>Click here...</B></A>"CRLF);
  3137.                 strcatbuff(rn,"</BODY>"CRLF);
  3138.                 strcatbuff(rn,"<!-- Created by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->"CRLF);
  3139.                 strcatbuff(rn,"</HTML>"CRLF);
  3140.                 
  3141.                 // changer la page
  3142.                 if (r->adr) { 
  3143.                   freet(r->adr); 
  3144.                   r->adr=NULL; 
  3145.                 }
  3146.                 r->adr=rn;
  3147.                 r->size=strlen(r->adr);
  3148.                 strcpybuff(r->contenttype,"text/html");
  3149.               }
  3150.             }  // get_it==0
  3151.             
  3152.           }     // bloc
  3153.           // erreur HTTP (ex: 404, not found)
  3154.         } else if (
  3155.           (r->statuscode==412)
  3156.           || (r->statuscode==416)
  3157.           ) {    // Precondition Failed, c'est α dire pour nous redemander TOUT le fichier
  3158.           if (fexist(liens[ptr]->sav)) {
  3159.             remove(liens[ptr]->sav);    // Eliminer
  3160.             if (!fexist(liens[ptr]->sav)) {  // Bien ΘliminΘ? (sinon on boucle..)
  3161. #if HDEBUG
  3162.               printf("Partial content NOT up-to-date, reget all file for %s\n",liens[ptr]->sav);
  3163. #endif
  3164.               if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  3165.                 //if (opt->errlog) {
  3166.                 fspc(opt->errlog,"debug"); fprintf(opt->errlog,"Partial file reget (%s) for %s%s"LF,r->msg,urladr,urlfil);
  3167.                 test_flush;
  3168.               }
  3169.               // enregistrer le MEME lien (MACRO)
  3170.               liens_record(liens[ptr]->adr,liens[ptr]->fil,liens[ptr]->sav,"","");
  3171.               if (liens[lien_tot]!=NULL) {    // OK, pas d'erreur
  3172.                 liens[lien_tot]->testmode=liens[ptr]->testmode;          // mode test?
  3173.                 liens[lien_tot]->link_import=0;       // pas mode import
  3174.                 liens[lien_tot]->depth=liens[ptr]->depth;
  3175.                 liens[lien_tot]->pass2=max(liens[ptr]->pass2,numero_passe);
  3176.                 liens[lien_tot]->retry=liens[ptr]->retry;
  3177.                 liens[lien_tot]->premier=liens[ptr]->premier;
  3178.                 liens[lien_tot]->precedent=ptr;
  3179.                 lien_tot++;
  3180.                 //
  3181.                 // canceller lien actuel
  3182.                 error=1;
  3183.                 strcpybuff(liens[ptr]->adr,"!");  // caractΦre bidon (invalide hash)
  3184. #if HTS_HASH
  3185. #else
  3186.                 liens[ptr]->sav_len=-1;       // taille invalide
  3187. #endif
  3188.                 //
  3189.               } else {  // oups erreur, plus de mΘmoire!!
  3190.                 printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  3191.                 if (opt->errlog) {
  3192.                   fprintf(opt->errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  3193.                   test_flush;
  3194.                 }
  3195.                 //if (opt->getmode & 1) { if (fp) { fclose(fp); fp=NULL; } }
  3196.                 XH_uninit;    // dΘsallocation mΘmoire & buffers
  3197.                 return 0;
  3198.               } 
  3199.             } else {
  3200.               if (opt->errlog!=NULL) {
  3201.                 fspc(opt->errlog,"error"); fprintf(opt->errlog,"Can not remove old file %s"LF,urlfil);
  3202.                 test_flush;
  3203.               }
  3204.             }
  3205.           } else {
  3206.             if (opt->errlog!=NULL) {
  3207.               fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Unexpected 412/416 error (%s) for %s%s"LF,r->msg,urladr,urlfil);
  3208.               test_flush;
  3209.             }
  3210.           }
  3211.         } else if (r->statuscode!=200) {
  3212.           int can_retry=0;
  3213.           
  3214.           // cas o∙ l'on peut reessayer
  3215.           // -2=timeout -3=rateout (interne α httrack)
  3216.           switch(r->statuscode) {
  3217.             //case -1: can_retry=1; break;
  3218.           case -2: if (opt->hostcontrol) {    // timeout et retry ΘpuisΘs
  3219.             if ((opt->hostcontrol & 1) && (liens[ptr]->retry<=0)) {
  3220.               if ((opt->debug>1) && (opt->log!=NULL)) {
  3221.                 fspc(opt->log,"debug"); fprintf(opt->log,"Link banned: %s%s"LF,urladr,urlfil); test_flush;
  3222.               }
  3223.               host_ban(opt,liens,ptr,lien_tot,back,back_max,jump_identification(urladr));
  3224.               if ((opt->debug>1) && (opt->log!=NULL)) {
  3225.                 fspc(opt->log,"debug"); fprintf(opt->log,"Info: previous log - link banned: %s%s"LF,urladr,urlfil); test_flush;
  3226.               }
  3227.             } else can_retry=1;
  3228.                    } else can_retry=1;
  3229.             break;
  3230.           case -3: if ((opt->hostcontrol) && (liens[ptr]->retry<=0)) {    // too slow
  3231.             if (opt->hostcontrol & 2) {
  3232.               if ((opt->debug>1) && (opt->log!=NULL)) {
  3233.                 fspc(opt->log,"debug"); fprintf(opt->log,"Link banned: %s%s"LF,urladr,urlfil); test_flush;
  3234.               }
  3235.               host_ban(opt,liens,ptr,lien_tot,back,back_max,jump_identification(urladr));
  3236.               if ((opt->debug>1) && (opt->log!=NULL)) {
  3237.                 fspc(opt->log,"debug"); fprintf(opt->log,"Info: previous log - link banned: %s%s"LF,urladr,urlfil); test_flush;
  3238.               }
  3239.             } else can_retry=1;
  3240.                    } else can_retry=1;
  3241.             break;
  3242.           case -4:            // connect closed
  3243.             can_retry=1;
  3244.             break;
  3245.           case -5:            // other (non fatal) error
  3246.             can_retry=1;
  3247.             break;
  3248.           case -6:            // bad SSL handskake
  3249.             can_retry=1;
  3250.             break;
  3251.           case 408: case 409: case 500: case 502: case 504: can_retry=1;
  3252.             break;
  3253.           }
  3254.           
  3255.           if ( strcmp(liens[ptr]->fil,"/primary") != 0 ) {  // no primary (internal page 0)
  3256.             if ((liens[ptr]->retry<=0) || (!can_retry) ) {  // retry ΘpuisΘs (ou retry impossible)
  3257.               if (opt->errlog) {
  3258.                 if ((opt->retry>0) && (can_retry)){
  3259.                   fspc(opt->errlog,"error"); 
  3260.                   fprintf(opt->errlog,"\"%s\" (%d) after %d retries at link %s%s (from %s%s)"LF,r->msg,r->statuscode,opt->retry,urladr,urlfil,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil);
  3261.                 } else {
  3262.                   if (r->statuscode==-10) {    // test OK
  3263.                     if ((opt->debug>0) && (opt->errlog!=NULL)) {
  3264.                       fspc(opt->errlog,"info"); 
  3265.                       fprintf(opt->errlog,"Test OK at link %s%s (from %s%s)"LF,urladr,urlfil,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil);
  3266.                     }
  3267.                   } else {
  3268.                     if (strcmp(urlfil,"/robots.txt")) {       // ne pas afficher d'infos sur robots.txt par dΘfaut
  3269.                       fspc(opt->errlog,"error"); 
  3270.                       fprintf(opt->errlog,"\"%s\" (%d) at link %s%s (from %s%s)"LF,r->msg,r->statuscode,urladr,urlfil,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil);
  3271.                     } else {
  3272.                       if (opt->debug>1) {
  3273.                         fspc(opt->errlog,"info"); fprintf(opt->errlog,"No robots.txt rules at %s"LF,urladr);
  3274.                         test_flush;
  3275.                       }
  3276.                     }
  3277.                   }
  3278.                 }
  3279.                 test_flush;
  3280.               }
  3281.               
  3282.               // NO error in trop level
  3283.               // due to the "no connection -> previous restored" hack
  3284.               // This prevent the engine from wiping all data if the website has been deleted (or moved)
  3285.               // since last time (which is quite annoying)
  3286.               if (liens[ptr]->precedent != 0) {
  3287.                 // ici on teste si on doit enregistrer la page tout de mΩme
  3288.                 if (opt->errpage) {
  3289.                   store_errpage=1;
  3290.                 }
  3291.               } else {
  3292.                 if (strcmp(urlfil,"/robots.txt") != 0) {
  3293.                 /*
  3294.                 This is an error caused by a link entered by the user
  3295.                 That is, link(s) entered by user are invalid (404, 500, connect error, proxy error->.)
  3296.                 If all links entered are invalid, the session failed and we will attempt to restore
  3297.                 the previous one
  3298.                 Example: Try to update a website which has been deleted remotely: this may delete
  3299.                 the website locally, which is really not desired (especially if the website disappeared!)
  3300.                 With this hack, the engine won't wipe local files (how clever)
  3301.                   */
  3302.                   HTS_STAT.stat_errors_front++;
  3303.                 }
  3304.               }
  3305.               
  3306.             } else {    // retry!!
  3307.               if (opt->debug>0 && opt->errlog != NULL) {  // on fera un alert si le retry Θchoue               
  3308.                 fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Retry after error %d (%s) at link %s%s (from %s%s)"LF,r->statuscode,r->msg,urladr,urlfil,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil);
  3309.                 test_flush;
  3310.               }
  3311.               // redemander fichier
  3312.               liens_record(urladr,urlfil,savename,"","");
  3313.               if (liens[lien_tot]!=NULL) {    // OK, pas d'erreur
  3314.                 liens[lien_tot]->testmode=liens[ptr]->testmode;          // mode test?
  3315.                 liens[lien_tot]->link_import=0;       // pas mode import
  3316.                 liens[lien_tot]->depth=liens[ptr]->depth;
  3317.                 liens[lien_tot]->pass2=max(liens[ptr]->pass2,numero_passe);
  3318.                 liens[lien_tot]->retry=liens[ptr]->retry-1;    // moins 1 retry!
  3319.                 liens[lien_tot]->premier=liens[ptr]->premier;
  3320.                 liens[lien_tot]->precedent=liens[ptr]->precedent;
  3321.                 lien_tot++;
  3322.               } else {  // oups erreur, plus de mΘmoire!!
  3323.                 printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  3324.                 if (opt->errlog) {
  3325.                   fspc(opt->errlog,"panic"); 
  3326.                   fprintf(opt->errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  3327.                   test_flush;
  3328.                 }
  3329.                 //if (opt->getmode & 1) { if (fp) { fclose(fp); fp=NULL; } }
  3330.                 XH_uninit;    // dΘsallocation mΘmoire & buffers
  3331.                 return 0;
  3332.               } 
  3333.             }
  3334.           } else {
  3335.             if (opt->errlog) {
  3336.               if (opt->debug>1) {
  3337.                 fspc(opt->errlog,"info"); 
  3338.                 fprintf(opt->errlog,"Info: no robots.txt at %s%s"LF,urladr,urlfil);
  3339.               }
  3340.             }
  3341.           }
  3342.           if (!store_errpage) {
  3343.             if (r->adr) {     // dΘsalloc
  3344.               freet(r->adr); 
  3345.               r->adr=NULL; 
  3346.             }
  3347.             error=1;  // erreur!
  3348.           }
  3349.         }
  3350.         // FIN rattrapage des 301,302,307..
  3351.         // ------------------------------------------------------------
  3352.         
  3353.       }  // if !error
  3354.       
  3355.       
  3356.       /* Apply changes */
  3357.       ENGINE_SAVE_CONTEXT();
  3358.       
  3359.       return 0;
  3360.       
  3361.       
  3362. }
  3363.  
  3364.  
  3365.  
  3366. /*
  3367.   Wait for next file and
  3368.   check 301, 302, .. statuscodes (moved)
  3369. */
  3370. int hts_mirror_wait_for_next_file(htsmoduleStruct* str, htsmoduleStructExtended* stre) {
  3371.   /* Load engine variables */
  3372.   ENGINE_LOAD_CONTEXT();
  3373.   /* */
  3374.   int b;
  3375.   int n;
  3376.   
  3377. #if BDEBUG==1
  3378.   printf("\nBack test..\n");
  3379. #endif
  3380.   
  3381.   // pause/lock files
  3382.   {
  3383.     int do_pause=0;
  3384.     
  3385.     // user pause lockfile : create hts-paused.lock --> HTTrack will be paused
  3386.     if (fexist(fconcat(opt->path_log,"hts-stop.lock"))) {
  3387.       // remove lockfile
  3388.       remove(fconcat(opt->path_log,"hts-stop.lock"));
  3389.       if (!fexist(fconcat(opt->path_log,"hts-stop.lock"))) {
  3390.         do_pause=1;
  3391.       }
  3392.     }
  3393.     
  3394.     // after receving N bytes, pause
  3395.     if (opt->fragment>0) {
  3396.       if ((HTS_STAT.stat_bytes-stat_fragment) > opt->fragment) {
  3397.         do_pause=1;
  3398.       }
  3399.     }
  3400.     
  3401.     // pause?
  3402.     if (do_pause) {
  3403.       if ( (opt->debug>0) && (opt->log!=NULL) ) {
  3404.         fspc(opt->log,"info"); fprintf(opt->log,"engine: pause requested.."LF);
  3405.       }
  3406.       while (back_nsoc(back,back_max)>0) {                  // attendre fin des transferts
  3407.         back_wait(back,back_max,opt,cache,HTS_STAT.stat_timestart);
  3408.         Sleep(200);
  3409. #if HTS_ANALYSTE
  3410.         {
  3411.           back_wait(back,back_max,opt,cache,HTS_STAT.stat_timestart);
  3412.           
  3413.           // Transfer rate
  3414.           engine_stats();
  3415.           
  3416.           // Refresh various stats
  3417.           HTS_STAT.stat_nsocket=back_nsoc(back,back_max);
  3418.           HTS_STAT.stat_errors=fspc(NULL,"error");
  3419.           HTS_STAT.stat_warnings=fspc(NULL,"warning");
  3420.           HTS_STAT.stat_infos=fspc(NULL,"info");
  3421.           HTS_STAT.nbk=backlinks_done(liens,lien_tot,ptr);
  3422.           HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,back,back_max);
  3423.           
  3424.           b=0;
  3425.           if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)
  3426.             || !back_checkmirror(opt)) {
  3427.             if (opt->errlog) {
  3428.               fspc(opt->errlog,"info"); fprintf(opt->errlog,"Exit requested by shell or user"LF);
  3429.               test_flush;
  3430.             }
  3431.             *stre->exit_xh_=1;  // exit requested
  3432.             XH_uninit;
  3433.             return 0;
  3434.           }
  3435.         }
  3436. #endif
  3437.       }
  3438.       // On dΘsalloue le buffer d'enregistrement des chemins crΘΘe, au cas o∙ pendant la pause
  3439.       // l'utilisateur ferait un rm -r aprΦs avoir effectuΘ un tar
  3440.       // structcheck_init(1);
  3441.       {
  3442.         FILE* fp = fopen(fconcat(opt->path_log,"hts-paused.lock"),"wb");
  3443.         if (fp) {
  3444.           fspc(fp,"info");  // dater
  3445.           fprintf(fp,"Pause"LF"HTTrack is paused after retreiving "LLintP" bytes"LF"Delete this file to continue the mirror->.."LF""LF"",(LLint)HTS_STAT.stat_bytes);
  3446.           fclose(fp);
  3447.         }
  3448.       }
  3449.       stat_fragment=HTS_STAT.stat_bytes;
  3450.       /* Info for wrappers */
  3451.       if ( (opt->debug>0) && (opt->log!=NULL) ) {
  3452.         fspc(opt->log,"info"); fprintf(opt->log,"engine: pause: %s"LF,fconcat(opt->path_log,"hts-paused.lock"));
  3453.       }
  3454. #if HTS_ANALYSTE
  3455.       hts_htmlcheck_pause(fconcat(opt->path_log,"hts-paused.lock"));
  3456. #else
  3457.       while (fexist(fconcat(opt->path_log,"hts-paused.lock"))) {
  3458.         //back_wait(back,back_max,opt,cache,HTS_STAT.stat_timestart);   inutile!! (plus de sockets actives)
  3459.         Sleep(1000);
  3460.       }
  3461. #endif
  3462.     }
  3463.     //
  3464.   }
  3465.   // end of pause/lock files
  3466.   
  3467. #if HTS_ANALYSTE
  3468.   // changement dans les prΘfΘrences
  3469.   /*
  3470.   if (_hts_setopt) {
  3471.   copy_htsopt(_hts_setopt,opt);    // copier au besoin
  3472.   _hts_setopt=NULL;                 // effacer callback
  3473.   }
  3474.   */
  3475.   if (_hts_addurl) {
  3476.     char add_adr[HTS_URLMAXSIZE*2];
  3477.     char add_fil[HTS_URLMAXSIZE*2];
  3478.     while(*_hts_addurl) {
  3479.       char add_url[HTS_URLMAXSIZE*2];
  3480.       add_adr[0]=add_fil[0]=add_url[0]='\0';
  3481.       if (!link_has_authority(*_hts_addurl))
  3482.         strcpybuff(add_url,"http://");          // ajouter http://
  3483.       strcatbuff(add_url,*_hts_addurl);
  3484.       if (ident_url_absolute(add_url,add_adr,add_fil)>=0) {
  3485.         // ----Ajout----
  3486.         // noter NOUVEAU lien
  3487.         char add_sav[HTS_URLMAXSIZE*2];
  3488.         // calculer lien et Θventuellement modifier addresse/fichier
  3489.         if (url_savename(add_adr,add_fil,add_sav,NULL,NULL,NULL,NULL,opt,liens,lien_tot,back,back_max,cache,hash,ptr,numero_passe)!=-1) { 
  3490.           if (hash_read(hash,add_sav,"",0,0)<0) {      // n'existe pas dΘja
  3491.             // enregistrer lien (MACRO)
  3492.             liens_record(add_adr,add_fil,add_sav,"","");
  3493.             if (liens[lien_tot]!=NULL) {    // OK, pas d'erreur
  3494.               liens[lien_tot]->testmode=0;          // mode test?
  3495.               liens[lien_tot]->link_import=0;       // mode normal
  3496.               liens[lien_tot]->depth=opt->depth;
  3497.               liens[lien_tot]->pass2=max(0,numero_passe);
  3498.               liens[lien_tot]->retry=opt->retry;
  3499.               liens[lien_tot]->premier=lien_tot;
  3500.               liens[lien_tot]->precedent=lien_tot;
  3501.               lien_tot++;
  3502.               //
  3503.               if ((opt->debug>0) && (opt->log!=NULL)) {
  3504.                 fspc(opt->log,"info"); fprintf(opt->log,"Link added by user: %s%s"LF,add_adr,add_fil); test_flush;
  3505.               }
  3506.               //
  3507.             } else {  // oups erreur, plus de mΘmoire!!
  3508.               printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  3509.               if (opt->errlog) {
  3510.                 fprintf(opt->errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  3511.                 test_flush;
  3512.               }
  3513.               //if (opt->getmode & 1) { if (fp) { fclose(fp); fp=NULL; } }
  3514.               XH_uninit;    // dΘsallocation mΘmoire & buffers
  3515.               return 0;
  3516.             }
  3517.           } else {
  3518.             if ( (opt->debug>0) && (opt->errlog!=NULL) ) {
  3519.               fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Existing link %s%s not added after user request"LF,add_adr,add_fil);
  3520.               test_flush;
  3521.             }
  3522.           }
  3523.           
  3524.         }
  3525.       } else {
  3526.         if (opt->errlog) {
  3527.           fspc(opt->errlog,"error");
  3528.           fprintf(opt->errlog,"Error during URL decoding for %s"LF,add_url);
  3529.           test_flush;
  3530.         }
  3531.       }
  3532.       // ----Fin Ajout----
  3533.       _hts_addurl++;                  // suivante
  3534.     }
  3535.     _hts_addurl=NULL;           // libΘrer _hts_addurl
  3536.   }
  3537.   // si une pause a ΘtΘ demandΘe
  3538.   if (_hts_setpause) {
  3539.     // index du lien actuel
  3540.     int b=back_index(back,back_max,urladr,urlfil,savename);
  3541.     if (b<0) b=0;    // forcer pour les stats
  3542.     while(_hts_setpause) {    // on fait la pause..
  3543.       back_wait(back,back_max,opt,cache,HTS_STAT.stat_timestart);
  3544.       
  3545.       // Transfer rate
  3546.       engine_stats();
  3547.       
  3548.       // Refresh various stats
  3549.       HTS_STAT.stat_nsocket=back_nsoc(back,back_max);
  3550.       HTS_STAT.stat_errors=fspc(NULL,"error");
  3551.       HTS_STAT.stat_warnings=fspc(NULL,"warning");
  3552.       HTS_STAT.stat_infos=fspc(NULL,"info");
  3553.       HTS_STAT.nbk=backlinks_done(liens,lien_tot,ptr);
  3554.       HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,back,back_max);
  3555.       
  3556.       if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) {
  3557.         if (opt->errlog) {
  3558.           fspc(opt->errlog,"info"); fprintf(opt->errlog,"Exit requested by shell or user"LF);
  3559.           test_flush;
  3560.         }
  3561.         *stre->exit_xh_=1;  // exit requested
  3562.         XH_uninit;
  3563.         return 0;
  3564.       }
  3565.       if (back_nsoc(back,back_max)==0)
  3566.         Sleep(250);  // tite pause
  3567.     }
  3568.   }
  3569. #endif
  3570.   
  3571.   // si le fichier n'est pas en backing, le mettre..
  3572.   if (!back_exist(back,back_max,urladr,urlfil,savename)) {
  3573. #if BDEBUG==1
  3574.     printf("crash backing: %s%s\n",liens[ptr]->adr,liens[ptr]->fil);
  3575. #endif
  3576.     if (back_add(back,back_max,opt,cache,urladr,urlfil,savename,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil,liens[ptr]->testmode,&liens[ptr]->pass2)==-1) {
  3577.       printf("PANIC! : Crash adding error, unexpected error found.. [%d]\n",__LINE__);
  3578. #if BDEBUG==1
  3579.       printf("error while crash adding\n");
  3580. #endif
  3581.       if (opt->errlog) {
  3582.         fspc(opt->errlog,"error"); fprintf(opt->errlog,"Unexpected backing error for %s%s"LF,urladr,urlfil);
  3583.         test_flush;
  3584.       } 
  3585.       
  3586.     }
  3587.   }
  3588.   
  3589. #if BDEBUG==1
  3590.   printf("test number of socks\n");
  3591. #endif
  3592.   
  3593.   // ajouter autant de socket qu'on peut ajouter
  3594.   n=opt->maxsoc-back_nsoc(back,back_max);
  3595. #if BDEBUG==1
  3596.   printf("%d sockets available for backing\n",n);
  3597. #endif
  3598.   
  3599. #if HTS_ANALYSTE
  3600.   if ((n>0) && (!_hts_setpause)) {   // si sockets libre et pas en pause, ajouter
  3601. #else
  3602.     if (n>0) {                         // si sockets libre
  3603. #endif
  3604.       // remplir autant que l'on peut le cache (backing)
  3605.       back_fillmax(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot);
  3606.     }
  3607.     
  3608.     // index du lien actuel
  3609.     /*
  3610.     b=back_index(back,back_max,urladr,urlfil,savename);
  3611.     
  3612.       if (b>=0) 
  3613.     */
  3614.     {
  3615.       // ------------------------------------------------------------
  3616.       // attendre que le fichier actuel soit prΩt - BOUCLE D'ATTENTE
  3617.       do {
  3618.         
  3619.         // index du lien actuel
  3620.         b=back_index(back,back_max,urladr,urlfil,savename);
  3621. #if BDEBUG==1
  3622.         printf("back index %d, waiting\n",b);
  3623. #endif
  3624.         // Continue to the loop if link still present
  3625.         if (b<0)
  3626.           continue;
  3627.         
  3628.         // Receive data
  3629.         if (back[b].status>0)
  3630.           back_wait(back,back_max,opt,cache,HTS_STAT.stat_timestart);
  3631.         
  3632.         // Continue to the loop if link still present
  3633.         b=back_index(back,back_max,urladr,urlfil,savename);
  3634.         if (b<0)
  3635.           continue;
  3636.         
  3637.         // Stop the mirror
  3638.         if (!back_checkmirror(opt)) {
  3639.           *stre->exit_xh_=1;  // exit requested
  3640.           XH_uninit;
  3641.           return 0;
  3642.         }
  3643.         
  3644.         // And fill the backing stack
  3645.         if (back[b].status>0)
  3646.           back_fillmax(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot);
  3647.         
  3648.         // Continue to the loop if link still present
  3649.         b=back_index(back,back_max,urladr,urlfil,savename);
  3650.         if (b<0)
  3651.           continue;
  3652.         
  3653.         // autres occupations de HTTrack: statistiques, boucle d'attente, etc.
  3654.         if ((opt->makestat) || (opt->maketrack)) {
  3655.           TStamp l=time_local();
  3656.           if ((int) (l-makestat_time) >= 60) {   
  3657.             if (makestat_fp != NULL) {
  3658.               fspc(makestat_fp,"info");
  3659.               fprintf(makestat_fp,"Rate= %d (/"LLintP") \11NewLinks= %d (/%d)"LF,(int) ((HTS_STAT.HTS_TOTAL_RECV-*stre->makestat_total_)/(l-makestat_time)), (LLint)HTS_STAT.HTS_TOTAL_RECV,(int) lien_tot-*stre->makestat_lnk_,(int) lien_tot);
  3660.               fflush(makestat_fp);
  3661.               *stre->makestat_total_=HTS_STAT.HTS_TOTAL_RECV;
  3662.               *stre->makestat_lnk_=lien_tot;
  3663.             }
  3664.             if (stre->maketrack_fp != NULL) {
  3665.               int i;
  3666.               fspc(stre->maketrack_fp,"info"); fprintf(stre->maketrack_fp,LF);
  3667.               for(i=0;i<back_max;i++) {
  3668.                 back_info(back,i,3,stre->maketrack_fp);
  3669.               }
  3670.               fprintf(stre->maketrack_fp,LF);
  3671.               
  3672.             }
  3673.             makestat_time=l;
  3674.           }
  3675.         }
  3676. #if HTS_ANALYSTE
  3677.         {
  3678.           int i;
  3679.           {
  3680.             char* s=hts_cancel_file("");
  3681.             if (strnotempty(s)) {    // fichier α canceller
  3682.               for(i=0;i<back_max;i++) {
  3683.                 if ((back[i].status>0)) {
  3684.                   if (strcmp(back[i].url_sav,s)==0) {  // ok trouvΘ
  3685.                     if (back[i].status != 1000) {
  3686. #if HTS_DEBUG_CLOSESOCK
  3687.                       DEBUG_W("user cancel: deletehttp\n");
  3688. #endif
  3689.                       if (back[i].r.soc!=INVALID_SOCKET) deletehttp(&back[i].r);
  3690.                       back[i].r.soc=INVALID_SOCKET;
  3691.                       back[i].r.statuscode=-1;
  3692.                       strcpybuff(back[i].r.msg,"Cancelled by User");
  3693.                       back[i].status=0;  // terminΘ
  3694.                     } else    // cancel ftp.. flag α 1
  3695.                       back[i].stop_ftp = 1;
  3696.                   }
  3697.                 }
  3698.               }
  3699.               s[0]='\0';
  3700.             }
  3701.           }
  3702.           
  3703.           // Transfer rate
  3704.           engine_stats();
  3705.           
  3706.           // Refresh various stats
  3707.           HTS_STAT.stat_nsocket=back_nsoc(back,back_max);
  3708.           HTS_STAT.stat_errors=fspc(NULL,"error");
  3709.           HTS_STAT.stat_warnings=fspc(NULL,"warning");
  3710.           HTS_STAT.stat_infos=fspc(NULL,"info");
  3711.           HTS_STAT.nbk=backlinks_done(liens,lien_tot,ptr);
  3712.           HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,back,back_max);
  3713.           
  3714.           if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) {
  3715.             if (opt->errlog) {
  3716.               fspc(opt->errlog,"info"); fprintf(opt->errlog,"Exit requested by shell or user"LF);
  3717.               test_flush;
  3718.             } 
  3719.             *stre->exit_xh_=1;  // exit requested
  3720.             XH_uninit;
  3721.             return 0;
  3722.           }
  3723.         }
  3724.         
  3725. #endif
  3726. #if HTS_POLL
  3727.         if ((opt->shell) || (opt->keyboard) || (opt->verbosedisplay) || (!opt->quiet)) {
  3728.           TStamp tl;
  3729.           *stre->info_shell_=1;
  3730.           
  3731.           /* Toggle with ENTER */
  3732.           if (!opt->quiet) {
  3733.             if (check_stdin()) {
  3734.               char com[256];
  3735.               linput(stdin,com,200);
  3736.               if (opt->verbosedisplay==2)
  3737.                 opt->verbosedisplay=1;
  3738.               else
  3739.                 opt->verbosedisplay=2;
  3740.               /* Info for wrappers */
  3741.               if ( (opt->debug>0) && (opt->log!=NULL) ) {
  3742.                 fspc(opt->log,"info"); fprintf(opt->log,"engine: change-options"LF);
  3743.               }
  3744. #if HTS_ANALYSTE
  3745.               hts_htmlcheck_chopt(opt);
  3746. #endif
  3747.             }
  3748.           }
  3749.           
  3750.           tl=time_local();
  3751.           
  3752.           // gΘnΘrer un message d'infos sur l'Θtat actuel
  3753.           if (opt->shell) {    // si shell
  3754.             if ((tl-*stre->last_info_shell_)>0) {    // toute les 1 sec
  3755.               FILE* fp=stdout;
  3756.               int a=0;
  3757.               *stre->last_info_shell_=tl;
  3758.               if (fexist(fconcat(opt->path_log,"hts-autopsy"))) {  // dΘbuggage: teste si le robot est vivant
  3759.                 // (oui je sais un robot vivant.. mais bon.. il a le droit de vivre lui aussi)
  3760.                 // (libΘrons les robots esclaves de l'internet!)
  3761.                 remove(fconcat(opt->path_log,"hts-autopsy"));
  3762.                 fp=fopen(fconcat(opt->path_log,"hts-isalive"),"wb");
  3763.                 a=1;
  3764.               }
  3765.               if ((*stre->info_shell_) || a) {
  3766.                 int i,j;
  3767.                 
  3768.                 fprintf(fp,"TIME %d"LF,(int) (tl-HTS_STAT.stat_timestart));
  3769.                 fprintf(fp,"TOTAL %d"LF,(int) HTS_STAT.stat_bytes);
  3770.                 fprintf(fp,"RATE %d"LF,(int) (HTS_STAT.HTS_TOTAL_RECV/(tl-HTS_STAT.stat_timestart)));
  3771.                 fprintf(fp,"SOCKET %d"LF,back_nsoc(back,back_max));
  3772.                 fprintf(fp,"LINK %d"LF,lien_tot);
  3773.                 {
  3774.                   LLint mem=0;
  3775.                   for(i=0;i<back_max;i++)
  3776.                     if (back[i].r.adr!=NULL)
  3777.                       mem+=back[i].r.size;
  3778.                     fprintf(fp,"INMEM "LLintP""LF,(LLint)mem);
  3779.                 }
  3780.                 for(j=0;j<2;j++) {  // passes pour ready et wait
  3781.                   for(i=0;i<back_max;i++) {
  3782.                     back_info(back,i,j+1,stdout);    // maketrack_fp a la place de stdout ?? // **
  3783.                   }
  3784.                 }
  3785.                 fprintf(fp,LF);
  3786.                 if (a)
  3787.                   fclose(fp);
  3788.                 io_flush;
  3789.               }
  3790.             }
  3791.           }  // si shell
  3792.           
  3793.         }  // si shell ou keyboard (option)
  3794.         //
  3795. #endif
  3796.       } while((b>=0) && (back[max(b,0)].status>0));
  3797.             
  3798.             
  3799.       // If link not found on the stack, it's because it has already been downloaded
  3800.       // in background
  3801.       // Then, skip it and go to the next one
  3802.       if (b<0) {
  3803.         if ((opt->debug>1) && (opt->log!=NULL)) {
  3804.           fspc(opt->log,"debug"); fprintf(opt->log,"link #%d is ready, no more on the stack, skipping: %s%s.."LF,ptr,urladr,urlfil);
  3805.           test_flush;
  3806.         }
  3807.         
  3808.         // prochain lien
  3809.         // ptr++;
  3810.         
  3811.         return 2; // goto jump_if_done;
  3812.         
  3813.       }
  3814.       /* link put in cache by the backing system for memory spare - reclaim */
  3815.       else if (back[b].finalized) {
  3816.         assertf(back[b].r.adr == NULL);
  3817.         /* read file in cache */
  3818.         back[b].r = cache_read_ro(opt,cache,back[b].url_adr,back[b].url_fil,back[b].url_sav, back[b].location_buffer);
  3819.         /* ensure correct location buffer set */
  3820.         back[b].r.location=back[b].location_buffer;
  3821.         if (back[b].r.statuscode == -1) {
  3822.           if (opt->errlog) {
  3823.             fspc(opt->errlog,"error"); fprintf(opt->errlog,"Unexpected error: %s%s not found anymore in cache"LF,back[b].url_adr,back[b].url_fil);
  3824.             test_flush;
  3825.           }
  3826.         } else {
  3827.           if ( (opt->debug>1) && (opt->log!=NULL) ) {
  3828.             fspc(opt->log,"debug"); fprintf(opt->log,"reclaim file %s%s (%d)"LF,back[b].url_adr,back[b].url_fil,back[b].r.statuscode); test_flush;
  3829.           }
  3830.         }
  3831.       }
  3832.             
  3833.             
  3834. #if HTS_ANALYSTE==2
  3835. #else
  3836.       //if (!opt->quiet) {  // petite animation
  3837.       if (!opt->verbosedisplay) {
  3838.         if (!opt->quiet) {
  3839.           static int roll=0;  /* static: ok */
  3840.           roll=(roll+1)%4;
  3841.           printf("%c\x0d",("/-\\|")[roll]);
  3842.           fflush(stdout);
  3843.         }
  3844.       } else if (opt->verbosedisplay==1) {
  3845.         if (back[b].r.statuscode==200)
  3846.           printf("%d/%d: %s%s ("LLintP" bytes) - OK\33[K\r",ptr,lien_tot,back[b].url_adr,back[b].url_fil,(LLint)back[b].r.size);
  3847.         else
  3848.           printf("%d/%d: %s%s ("LLintP" bytes) - %d\33[K\r",ptr,lien_tot,back[b].url_adr,back[b].url_fil,(LLint)back[b].r.size,back[b].r.statuscode);
  3849.         fflush(stdout);
  3850.       }
  3851.       //}
  3852. #endif
  3853.       // ------------------------------------------------------------
  3854.       // VΘrificateur d'intΘgritΘ
  3855. #if DEBUG_CHECKINT
  3856.       _CHECKINT(&back[b],"Retour de back_wait, aprΦs le while")
  3857.       {
  3858.         int i;
  3859.         for(i=0;i<back_max;i++) {
  3860.           char si[256];
  3861.           sprintf(si,"Test global aprΦs back_wait, index %d",i);
  3862.           _CHECKINT(&back[i],si)
  3863.         }
  3864.       }
  3865. #endif
  3866.       
  3867.       // copier structure rΘponse htsblk
  3868.       memcpy(r, &(back[b].r), sizeof(htsblk));
  3869.       r->location=stre->loc_;    // ne PAS copier location!! adresse, pas de buffer
  3870.       if (back[b].r.location) 
  3871.         strcpybuff(r->location,back[b].r.location);
  3872.       back[b].r.adr=NULL;    // ne pas faire de desalloc ensuite
  3873.       
  3874.       // libΘrer emplacement backing
  3875.       back_maydelete(opt,back,b);
  3876.       
  3877.       // progression
  3878. #if 0
  3879.       if (opt->aff_progress) {
  3880.         TStamp tl=time_local();
  3881.         if ((tl-HTS_STAT.stat_timestart)>0) {
  3882.           char s[32];
  3883.           int i=0;
  3884.           lastime=tl;
  3885.           _CLRSCR; _GOTOXY("1","1");
  3886.           printf("Rate=%d B/sec\n",(int) (HTS_STAT.HTS_TOTAL_RECV/(tl-HTS_STAT.stat_timestart)));
  3887.           while(i<minimum(back_max,99)) {  // **
  3888.             if (back[i].status>=0) {  // loading..
  3889.               s[0]='\0';
  3890.               if (strlen(back[i].url_fil)>16)
  3891.                 strcatbuff(s,back[i].url_fil+strlen(back[i].url_fil)-16);       
  3892.               else
  3893.                 strncatbuff(s,back[i].url_fil,16);
  3894.               printf("%s : ",s);
  3895.               
  3896.               printf("[");
  3897.               if (back[i].r.totalsize>0) {
  3898.                 int p;
  3899.                 int j;
  3900.                 p=(int)((back[i].r.size*10)/back[i].r.totalsize);
  3901.                 p=minimum(10,p);
  3902.                 for(j=0;j<p;j++) printf("*");
  3903.                 for(j=0;j<(10-p);j++) printf("-");
  3904.               } else { 
  3905.                 printf(LLintP,(LLint)back[i].r.size);                      
  3906.               }
  3907.               printf("]");
  3908.               
  3909.               //} else if (back[i].status==0) {
  3910.               //  strcpybuff(s,"ENDED");
  3911.             } 
  3912.             printf("\n");
  3913.             i++;
  3914.           }
  3915.           io_flush;
  3916.         }
  3917.       }
  3918. #endif
  3919.       
  3920.       // dΘbug graphique
  3921. #if BDEBUG==2
  3922.       {
  3923.         char s[12];
  3924.         int i=0;
  3925.         _GOTOXY(1,1);
  3926.         printf("Rate=%d B/sec\n",(int) (HTS_STAT.HTS_TOTAL_RECV/(time_local()-HTS_STAT.stat_timestart)));
  3927.         while(i<minimum(back_max,160)) {
  3928.           if (back[i].status>0) {
  3929.             sprintf(s,"%d",back[i].r.size);
  3930.           } else if (back[i].status==0) {
  3931.             strcpybuff(s,"ENDED");
  3932.           } else 
  3933.             strcpybuff(s,"   -   ");
  3934.           while(strlen(s)<8) strcatbuff(s," ");
  3935.           printf("%s",s); io_flush;
  3936.           i++;
  3937.         }
  3938.       }
  3939. #endif
  3940.       
  3941.       
  3942. #if BDEBUG==1
  3943.       printf("statuscode=%d with %s / msg=%s\n",r->statuscode,r->contenttype,r->msg);
  3944. #endif
  3945.       
  3946.     }
  3947.     /*else {
  3948.     #if BDEBUG==1
  3949.     printf("back index error\n");
  3950.     #endif
  3951.     }
  3952.     */
  3953.     
  3954.     
  3955.     
  3956.     ENGINE_SAVE_CONTEXT();
  3957.     
  3958.     return 0;
  3959.     
  3960.     
  3961. }
  3962.  
  3963.  
  3964.